定义:使用多个专门的接口,而不是使用庞大臃肿的单一接口,接口尽量细化,接口中的方法尽量少。
问题:类A通过接口I依赖类B,类C通过接口I依赖类D,如果接口I对于类A和类B来说不是最小接口,则类B和类D必须
去实现他们不需要的方法。
解决:将臃肿的接口I拆分为独立的几个接口,类A和类C分别与他们需要的接口建立依赖关系。也就是采用接口隔离原则。
举个栗子:富人用手机和穷人用座机的故事。。。
情形一:手机的特点是发送短信、拨打电话、听音乐和观看视频,座机的特点是有线和拨打电话。我们如果不遵循接口隔离原则,
将这些特点统一放在一个接口Icommon里面,让手机类Mobile和座机类Phone分别实现这个接口。
1. 新建一个接口Icommon,包含有线、发送短信、拨打电话、听音乐和观看视频五个方法。代码如下:
2.新建一个手机类Mobile和一个座机类Phone,分别来实现接口Icommon。代码如下:
3. 新建一个富人类WealthMan,通过依赖接口ICommon调用相关的方法。代码如下:
4. 新建一个穷人类PoorMan,也让它依赖接口ICommon,调用相关的方法。代码如下:
5. 在类ISPFragment中分别使用类WealthMan和类PoorMan,实现富人使用手机和穷人使用座机的效果。代码如下:
6. 运行后的效果,如下:
以上实现方式可以看出,对于手机类Mobile和座机类Phone来说,虽然在接口中都存在他们用不到的方法(手机类用不到wired()方法,座机类用不到sendMessage()、listenToMusic()和watchVideo()方法),但由于实现了接口Icommon,所以必须要实现这些用不到的方法,试想一下,如果方法有很多的话,是不是显得接口过于臃肿?只要接口中出现的方法,只要类依赖于它,不管对这个类有没有用处,都要去实现这些方法,这显然不是很好的设计。 so,接口隔离原则就是来解决这样的问题,对接口ICommon进行合理的拆分。
情形二:将座机异于手机的特点(有线)放在接口ICommon1中,座机和手机的共同特点(拨打电话)放在接口ICommon2中,手机异于座机的特点(发送短信、听音乐和观看视频)放在接口ICommon3中。具体实现方式如下:
1.新建一个接口ICommon1,包含有线wired()方法。代码如下:
2.新建一个接口ICommon2,包含拨打电话calling() 方法。代码如下:
3.新建一个接口ICommon3,包含发送短信sendMessage()、听音乐listenToMusic()和观看视频watchVideo()三个方法。代码如下:
4.新建一个手机类Mobile1,同时实现接口ICommon2和接口ICommon3。代码如下:
5.新建一个座机类Phone1,同时实现接口ICommon1和接口ICommon2。代码如下:
6. 新建一个富人类WealthMan1,分别依赖接口ICommon2和接口ICommon3调用相关的方法。代码如下:
7. 新建一个穷人类PoorMan1,分别依赖接口ICommon1和接口ICommon2,调用相关的方法。代码如下:
8. 修改类ISPFragment,分别使用类WealthMan1和类PoorMan1,实现富人使用手机和穷人使用座机的效果。代码如下:
9. 运行后的效果,如下:
优化后的实现方式可以看出,如果为手机类和座机类建立专用的接口,就不会出现没必要实现的方法,另外也方便手机和座机特有功能的扩展,实现起来更加灵活。
原则:为各个类建立专用接口,而不要试图去建立一个很庞大的接口供所有依赖它的类去调用,因为这样会出现有些类并不需要
去实现的方法。接口是设计时对外部设定的“契约”,通过分散定义多个接口,可以预防外来变更的扩散,提高系统的灵活
性和可维护性。
注意:
1. 接口尽量小,但是要有限度。如果接口过于小,则会造成接口数量过多的问题,使设计复杂化;接口也不能太大,
那就违背了接口隔离原则。所以一定要适度。
2. 只有专注地为一个类提供定制服务,才能建立最小的依赖关系;
3. 提高内聚,减少对外交互。使接口用最少的方法去完成更多的事情。
接口隔离原则和单一职责原则的区别:
一、单一职责原则注重的是职责,而接口隔离原则注重的是对接口依赖的隔离;
二、单一职责原则主要是约束类,其次才是接口和方法,它针对的是程序中的实现和细节,
而接口隔离原则主要约束的是接口,主要针对的是抽象,对程序整体框架的构建。
我的Github地址:https://github.com/chenxkang