接口隔离原则的定义
那么什么是接口?接口分为两类:
- 实例接口(Object Interface)
在java中声明一个类,类也是一种接口。 - 类接口(Class Interface)
java中经常使用Interface来定义。
接口隔离原则有两种定义:
-
第一种定义: Clients should not be forced to depend upon interfaces that they don't use. 客户端不应该依赖它不需用的接口。
-
第二种定义:The dependency of one class to another one should depend on the smallest possible interface。类间的依赖关系应该建立在最小的接口上。
一个新事物的定义一般都是比较难理解的,晦涩难懂是正常的,否则那会让人家觉的你没有水平,这 也是一些国际厂商在国内忽悠的基础,不整些名词怎么能让你崇拜我呢?我们把这个定义剖析一下,先说 第一种定义客户端不应该依赖它不需要接口,那依赖什么?依赖它需要的接口,客户端需要什么接口就提 供什么借口,把不需要的接口剔除掉,那就需要对接口进行细化,保证其纯洁性;再看第二个定义,类间 的依赖关系应该建立在最小的接口上,它要求是最小的接口,也是要求接口细化,接口纯洁,与第一个定 义如出一辙,只是一个事物的两种不同描述。
我们可以把这两个定义概括为一句话:建立单一接口,不要建立臃肿庞大的接口。再通俗的一点讲: 接口尽量细化,同时接口中的方法尽量的少。看到这里大家有可能要疑惑了,这与单一职责原则不是相同 的吗?错,接口隔离原则与单一职责的定义的规则是不相同的,单一职责要求的是类和接口职责单一,注 重的是职责,没有要求接口的方法减少,例如一个职责可能包含 10 个方法,这 10 个方法都放在一个接口 中,并且提供给多个模块访问,各个模块按照规定的权限来访问,在系统外通过文档约束不使用的方法不 要访问,按照单一职责原则是允许的,按照接口隔离原则是不允许的,因为它要求“尽量使用多个专门的 接口”,专门的接口指什么?就是指提供给多个模块的接口,提供给几个模块就应该有几个接口,而不是建 立一个庞大的臃肿的接口,所有的模块可以来访问。
类图
未遵循接口隔离原则的设计:
接口未隔离遵循接口隔离原则的设计:
接口隔离举例说明
我们来举个例子来说明接口隔离原则到底对我们提出了什么要求。现在男生对小姑娘的称呼使用频率 最高的应该是“美女”了吧,我们今天来定义一下什么是美女:首先要面貌好看,其次是身材要窈窕,然 后要有气质,当然了,这三者各人的排列顺序不一样,总之要成为一名美女就必须具备:面貌、身材和气质,我们用类图类体现一下星探(当然,你也可以把你自己想想成星探)找美女的过程,看类图:
星探找美女类图定义了一个 IPettyGirl 接口,声明所有的美女都应该有 goodLooking、niceFigure 和 greatTemperament,然后又定义了一个抽象类 AbstractSearcher,其作用就是搜索美女然后展示信息,只 要美女都是按照这个规范定义,Searcher(星探)就轻松的多了,我们先来看美女的定义:
public interface IPettyGirl {
//要有姣好的面孔
public void goodLooking();
//要有好身材
public void niceFigure();
//要有气质
public void greatTemperament();
}
美女就是这样的一个定义,各位色狼别把口水流到了键盘上,然后我们看美女的实现类:
public class PettyGirl implements IPettyGirl {
private String name;
//美女都有名字
public PettyGirl(String _name){
this. name=_name;
}
//脸蛋漂亮
public void goodLooking() {
System. out.println(this. name + "---脸蛋很漂亮!");
}
//气质要好
public void greatTemperament() {
System. out.println(this. name + "---气质非常好!");
}
//身材要好
public void niceFigure() {
System. out.println(this. name + "---身材非常棒!");
}
}
然后我们来看 AbstractSearcher 类,这个类一般就是指星探这个行业了,源代码如下:
public abstract class AbstractSearcher {
protected IPettyGirl pettyGirl;
public AbstractSearcher(IPettyGirl _pettyGirl){
this.pettyGirl = _pettyGirl;
}
//搜索美女,列出美女信息
public abstract void show();
}
场景中的两个角色美女和星探都已经完成了,我们再来写个场景类,展示一下我们的这个过程:
public class Client {
//搜索并展示美女信息
public static void main(String[] args) {
//定义一个美女
IPettyGirl yanYan = new PettyGirl(" 嫣嫣");
AbstractSearcher searcher = new Searcher(yanYan);
searcher.show();
}
}
星探查找到美女,打印出美女的信息,源码如下:
public class Searcher extends AbstractSearcher{
public Searcher(IPettyGirl _pettyGirl){
super(_pettyGirl);
}
//展示美女的信息
public void show(){
System. out.println("--------美女的信息如下: ---------------");
//展示面容
super. pettyGirl.goodLooking();
//展示身材
super. pettyGirl.niceFigure();
//展示气质
super. pettyGirl.greatTemperament();
}
}
运行结果如下:
--------美女的信息如下: ---------------
嫣嫣---脸蛋很漂亮!
嫣嫣---身材非常棒!
嫣嫣---气质非常好!
采用接口隔离原则:重新修改一下类图:
采用接口隔离原则把原 IPettyGirl 接口拆分为两个接口,一种是外形美的美女 IGoodBodyGirl,这类美女的特点就是脸 蛋和身材极棒,超一流,但是没有审美素质,比如随地吐痰,出口就是 KAO,CAO 之类的,文化程度比较低; 另外一种是气质美的美女 IGreatTemperamentGirl,谈吐和修养都非常高。我们从一个比较臃肿的接口拆分 成了两个专门的接口,灵活性提高了,可维护性也增加了,不管以后是要外形美的美女还是气质美的美女 都可以轻松的通过 PettyGirl 定义。我们先看两种类型的美女接口:
public interface IGoodBodyGirl {
//要有姣好的面孔
public void goodLooking();
//要有好身材
public void niceFigure();
}
public interface IGreatTemperamentGirl {
//要有气质
public void greatTemperament();
}
实现类没有改变,只是实现类两个接口,源码如下:
public class PettyGirl implements IGoodBodyGirl,IGreatTemperamentGirl {
private String name;
//美女都有名字
public PettyGirl(String _name){
this. name=_name;
}
//脸蛋漂亮
public void goodLooking() {
System. out.println(this. name + "---脸蛋很漂亮!");
}
//气质要好
public void greatTemperament() {
System. out.println(this. name + "---气质非常好!");
}
//身材要好
public void niceFigure() {
System. out.println(this. name + "---身材非常棒!");
}
}
通过这样的改造以后,不管以后是要气质美女还是要外形美女,都可以保持接口的稳定。当然你可能 要说了,以后可能审美观点再发生改变,只有脸蛋好看就是美女,那这个 IGoodBody 接口还是要修改的呀, 确实是,但是设计时有限度的,不能无限的考虑未来的变更情况,否则就会陷入设计的泥潭中而不能自拔。 以上把一个臃肿的接口变更为两个独立的接口依赖的原则就是接口隔离原则,让 AbstractSearcher 依 赖两个专用的接口比依赖一个综合的接口要灵活。接口是我们设计时对外提供的契约,通过分散定义多个 接口,可以预防未来变更的扩散,提高系统的灵活性和可维护性。
总结
接口隔离原则的含义是:建立单一接口,不要建立庞大臃肿的接口,尽量细化接口,接口中的方法尽量少。也就是说,我们要为各个类建立专用的接口,而不要试图去建立一个很庞大的接口供所有依赖它的类去调用。
在程序设计中,依赖几个专用的接口要比依赖一个综合的接口更灵活。接口是设计时对外部设定的“契约”,通过分散定义多个接口,可以预防外来变更的扩散,提高系统的灵活性和可维护性。
说到这里,很多人会觉的接口隔离原则跟之前的单一职责原则很相似,其实不然。
其一,单一职责原则注重的是职责;而接口隔离原则注重对接口依赖的隔离。
其二,单一职责原则主要是约束类,其次才是接口和方法,它针对的是程序中的实现和细节;而接口隔离原则主要约束接口接口,主要针对抽象,针对程序整体框架的构建。
最佳实践
采用接口隔离原则对接口进行约束时,要注意以下几点:
- 接口尽量小,但是要有限度。对接口进行细化可以提高程序设计灵活性是不挣的事实,但是如果过小,则会造成接口数量过多,使设计复杂化。所以一定要适度。
- 为依赖接口的类定制服务,只暴露给调用的类它需要的方法,它不需要的方法则隐藏起来。只有专注地为一个模块提供定制服务,才能建立最小的依赖关系。
- 提高内聚,减少对外交互。使接口用最少的方法去完成最多的事情。
- 运用接口隔离原则,一定要适度,接口设计的过大或过小都不好。设计接口的时候,只有多花些时间去思考和筹划,才能准确地实践这一原则。
网友评论