服务器之家

服务器之家 > 正文

java的接口解耦方式

时间:2021-12-20 13:52     来源/作者:iamkila

java的接口解耦方式

我只想把抽象的东西说的具体,或者说,听起来简单些,明白些。。。

学过java的人都知道,java是单继承的,也就是说一个class只能继承一个类。

例如我们想制作一台有播放器的手机,那么我们先得制作一个播放器吧,再把播放器放进手机里。在java会怎么实现呢?如果使用继承,我们会先创建一个播放器类,播放器类里面含有播放歌曲功能(方法),创建一个手机类继承播放器类,重写播放器的播歌功能(不重写的话,会直接使用播放器自己定制的播放功能),这样,我们就可以使用手机的播歌功能了。

现在,我们想制作一台既有播歌功能,又有收音机功能的手机,那么我们该怎么办?难道我们又要让继承了播放器的手机再继承收音机?但是java是单继承的,行不通,这时,接口应运而生!

接口,乍一看就是包含几个方法的一个东西,它里面不包含具体实现的代码,只包含方法的返回类型,名称,参数列表,它代表的是一个功能的集合,只要实现了这个接口的类,他就具有了这些功能。

回到之前说的既有播歌又有收音机功能的手机,现在我们不把播放器和收音机封装成类了,我们把它们封装成接口(接口就是功能的集合),创建手机类,实现播放器和收音机接口,这样看起来,是不是有点像多继承?这违背了java的单继承原则吗?

其实没有,有些书里面提到的多重继承指的是多个实现接口。继承(extends),是一种 is-a 关系的,所谓is-a关系,就是类似于“手机是播放器”或者“手机是收音机”这样说法,但明显,我们不能说“手机既是播放器又是收音机”,那么“他究竟是播放器还是收音机?”,这时大家就会可能这样发问了,这就是java是单继承的原因。实现(implement),是一种hava-a关系的,所谓have-a就是具有“某一项功能“的意思,我们这时候会说“手机既有播放器功能,又有收音机功能”,这样的表达该明白了吧!让手机再添加其他功能,只要再让他实现那些功能接口就好了。

好像说了那么多还没说到正题~哈哈,其实举前面的例子我是想说明一个问题:只要一个方法操作的是类而非接口,那么你只能使用这个类及其之类。如果你想要将这个方法应用于不在此继承结构中的某个类,那么你就触霉头了。接口可以在很大程度上放宽这种限制,因此,他使我们可以编写可复用性更好的代码。——引用《thinking in java》的某一些话。

举例子

我需要一个闹钟,放在我床边,每天叫我起床。但是我家里没闹钟,只有一台有闹钟功能的手机和一台有闹钟功能的洗衣机。我需要的只是闹钟功能,我管他是什么,只要他能让我起床就好了。如果某一天我连手机都丢了,我能把洗衣机放在我床边叫我起床吗?当然可以,因为洗衣机实现了闹钟功能。所以,我们经常会这么做:把“闹钟”这个功能(而不是具体的某一项事物,如手机或者洗衣机)放在床边,如果我们想听洗衣机的闹钟声就摆洗衣机,如果想听手机的闹钟声就摆手机。

从上面的例子,我们传递的不是某个具体的对象,而是一个抽象的“闹钟功能”的概念,至于实际上传递的是什么参数,要看具体情况(取决于我想听哪一种闹钟声)。实际上,我们只关心“具有闹钟功能”这件事,我们不关心它是由谁实现的和怎样实现的,这就做到了“请求”和“实现”分离开来,这就是接口的解耦!

java接口解耦效果的理解

先看一段代码

?
1
2
3
4
5
6
7
8
9
10
public class A {
    public void say() {
        System.out.println("I am A");
    }
}
public class C {
    public void put(A a) {
        a.say();
    }
}

在C类里面想调用一个含有say功能的东西,就把A传入了,突然有一天,产品经理多了个需求,想让B这种类型也能在C中作为参数调用B的say,也即A,B这两种类型都能满足作为输入,

?
1
2
3
4
5
public class B {
    public void say() {
        System.out.println("I am B");
    }
}

那好烦,不仅要像上面一样新建B类,还要修改C的代码适配需求,例如改成下面这个样子,搞成重载的样子,万一产品经理又来要求把D,E,F...这些具有say功能的类可以当成参数输入,新建D,E,F这些类也就算了,难免嘛,问题是还要修改C的类,在里面再添加很多类似的修改,感觉耦合的很紧,代码写的太死板了,变动下需求就得改主程序C里面的代码,

?
1
2
3
4
5
6
7
8
public class C{
    public void put(A a) {
        a.say();
    }
    public void put(B b) {
        b.say();
    }
}

有没有其他的好办法?有,用接口的方法,例如下面

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public interface IBase {
    void say();
}
public class A implements IBase {
    @Override
    public void say() {
        System.out.println("I am A");
    }
}
public class B implements IBase {
    @Override
    public void say() {
        System.out.println("I am B");
    }
}
public class C {
    public void put(IBase base) {
        base.say();
    }
}

定义一个接口,IBase,让产品经理新加的需求B,D,E,F都实现这个类,并且把C类里的参数写成接口的形式(只要实现了我这个接口功能的都能传入),这样只要是实现了IBase接口的类,也即实现具备了实现接口say功能的任何类都可以传进来,所以以后只需要新建B,D,E,F时实现这个接口就行了,不需要在C类里面修改源代码。

这就大大降低了工作量,本质上就是降低了耦合度,体现了接口的解耦效果,这是一点关于对接口解耦作用的理解

以上为个人经验,希望能给大家一个参考,也希望大家多多支持服务器之家。

原文链接:https://blog.csdn.net/iamkila/article/details/7257303

标签:

相关文章

热门资讯

yue是什么意思 网络流行语yue了是什么梗
yue是什么意思 网络流行语yue了是什么梗 2020-10-11
背刺什么意思 网络词语背刺是什么梗
背刺什么意思 网络词语背刺是什么梗 2020-05-22
2020微信伤感网名听哭了 让对方看到心疼的伤感网名大全
2020微信伤感网名听哭了 让对方看到心疼的伤感网名大全 2019-12-26
2021年耽改剧名单 2021要播出的59部耽改剧列表
2021年耽改剧名单 2021要播出的59部耽改剧列表 2021-03-05
苹果12mini价格表官网报价 iPhone12mini全版本价格汇总
苹果12mini价格表官网报价 iPhone12mini全版本价格汇总 2020-11-13
返回顶部