六大设计原则之四:接口隔离原则

定义

接口隔离原则(Interface Segregation Principle, ISP),定义为:

  1. Clients should not be forced to depend upon interfaces that they don’t use. (客户端不应该依赖它不需要的接口。)
  2. The dependency of one class to another one should depend on the smallest possible interface. (类间的依赖关系应该建立在最小的接口上。)

接口隔离原则是对接口的使用进行约束规范的一个原则,它告诉我们要想把接口用好,关键在于隔离。隔离,指断绝接触、断绝往来。那么我们使用接口时,要隔离什么东西呢?对于上述定义的第1点,“客户端不应该依赖它不需要的接口”,这里的隔离是指客户端和它不需要的接口隔离,也就是客户端不要使用它不需要的接口,这个很容易理解,在实践中也很容易实现。我们着重看一下第2点,“类间的依赖关系应该建立在最小的接口上”,它要求“最小的接口”,也就是该接口中没有多余的方法,所以这里的隔离是指和多余的方法隔离。

综上所述,接口隔离原则告诉我们,不要把一大堆方法塞进一个接口里,导致这个接口变得臃肿无比。应该要根据实际需要,让接口中只有用得上的方法,也就是说要细化我们的接口

好处

现在我们知道,接口隔离原则的要点,就是要细化我们的接口。那么这样做具体有什么好处呢?主要有四个好处,分别是:1.避免接口污染;2.提高灵活性;3.提供定制服务;4.实现高内聚。下面就来详细说一下接口隔离原则的好处。

避免接口污染

一个类如果要实现一个接口,那么就要实现这个接口要求的所有方法,如果这个接口里面包含这个类不需要的方法,那么就会造成接口污染,这是不好的设计,会对系统留下隐患。

比如说我们有一个枪的接口,枪有两个属性:扳机和子弹。枪有一个功能:射杀。其接口如下:

@protocol IGun <NSObject>
@property (strong,nonatomic) id trigger;//扳机
@property (strong,nonatomic) id bullet;//子弹
- (void)shot;//射杀
@end

然后我们现在需要一个玩具枪的类。玩具枪有扳机也有子弹,只是不能射杀。为了图方便,我们直接用IGun这个接口来实现我们的玩具枪:

#import "IGun.h"
@interface ToyGun : NSObject<IGun>
@end

@implementation ToyGun
@synthesize trigger = _trigger,bullet = _bullet;
- (void)shot{
    //空实现,什么也不做
}
@end

玩具枪是不能射杀的,但是由于它实现了IGun这个接口,所以只能空实现它并不需要的shot方法,于是玩具枪这个类就被污染了。这好像也没有什么不妥,但是这是有隐患的,因为玩具枪一旦实现了IGun接口,那么在程序里它就代表一把能射杀的枪。假设在后面突然遇到了一个老虎,唯一保命的方法就是拿枪射杀这个老虎,结果你拿到的是你之前为了图方便做的ToyGun,那么你面临的就是灭顶之灾。

提高灵活性

一个类是可以同时实现多个接口的,所以将一个臃肿的接口分割为若干个小接口,通过小接口的不同组合可以满足更多的需求。

举个例子。我们现在需要一个代表美女的接口,美女的标准也很明确:面貌、身材和气质,那么我们的美女接口就出来了:

@protocol IPrettyGirl <NSObject>
- (void)goodLooking;//好面貌
- (void)niceFigure;//好身材
- (void)greatTemperament;//好气质
@end

这并没有什么问题。但是在现实中,一定是要美貌和气质兼备的才算美女吗?非也,其实也有长得不好看,但是气质很好的气质美女的,当然也有没有气质但是长得好看的美女。这样上面的接口就不适用了,因为按照上面的的接口,只有长得好看而且气质好的才算美女。

可以通过细化这个接口解决这个问题。上述的接口可以一分为二:

只有外貌好的美女:

@protocol IGoodBodyGirl <NSObject>
- (void)goodLooking;//好面貌
- (void)niceFigure;//好身材
@end

只有气质好的美女:

@protocol IGreatTemperamentGirl <NSObject>
- (void)greatTemperament;//好气质
@end

然后通过这两个接口的不同组合,就能满足外貌美女、气质美女和外貌气质俱佳的美女的不同需求了。所以,细化接口可以让我们的接口更加灵活,满足更多需求。

提供定制服务

什么是定制服务?定制服务就是单独为一个个体提供优良的服务。我们在做系统设计时也需要考虑对系统之间或模块之间的接口提供定制服务。提供定制服务就必然有一个需求:只提供访问者需要的方法。这也是可以通过细化接口实现的。

比如我们开发了一个图书管理系统,其中有一个查询图书的接口:

@protocol IBookSearcher <NSObject>
- (void)searchByAuthor;//根据作者搜索
- (void)searchByTitle;//根据书名搜索
- (void)searchByCatagory;//根据分类搜索
- (void)complexSearch;//复杂的搜索
@end

我们的图书馆管理系统的访问者有管理人员和公网,其中complexSearch方法非常损耗服务器的性能,它只提供给管理人员使用。其他方法管理人员和公网都可以使用。公网这部分是另一个项目组在开发的,所以当时我们口头上跟公网项目组说明不能在公网上调用complexSearch这个方法。图书馆管理系统上线后,有一天发现系统速度非常慢,在熬了一个通宵排查后,发现是由于公网项目组某个程序员的疏忽,把complexSearch方法公布到了公网中...

显然通过口头的方式说哪一个方法不能调用是不管用的,要想彻底解决这个问题,还是得通过细化接口,为访问者定制专有的接口才行。那么上述的接口可以一分为二:

简单的搜索:

@protocol ISimpleBookSearcher <NSObject>
- (void)searchByAuthor;//根据作者搜索
- (void)searchByTitle;//根据书名搜索
- (void)searchByCatagory;//根据分类搜索
@end

复杂的搜索:

@protocol IComplexBookSearcher <NSObject>
- (void)complexSearch;//复杂的搜索
@end

这样我们就可以分别给管理人员和公网定制接口了:

  1. 给管理人员提供ISimpleBookSearcherIComplexBookSearcher两个接口;
  2. 给外网提供ISimpleBookSearcher这个接口。

所谓的定制服务,就是通过细化接口,实现给不同的客户提供不同的接口的目的。定制服务可以有效避免因为给客户提供了多余的方法而造成的风险。

高内聚

什么是高内聚?高内聚就是提高接口、类、模块的处理能力,减少对外的交互。比如说,你告诉你的下属“一个小时之内去月球搬一块石头回来”,然后你就躺在海滩上晒着太阳喝着果汁,一个小时之后你的下属就搬着一块月亮上的石头回来给你了。这种不讲任何条件,不需要你关心任何细节,立即完成任务的行为就是高内聚的表现。

具体到接口中,还是尽量细化你的接口。接口是对外界的承诺,承诺越少对系统的开发越有利,变更的风险也就越少,同时也有利于降低成本。

注意

接口隔离原则和单一职责原则非常类似。单一职责原则要求接口的职责是单一的,而接口隔离原则要求接口尽量细化,它们有异曲同工之妙,都是要让我们的接口功能尽量单一,尽量小。

但是,单一职责原则的着重点是在“职责”,而接口隔离原则只单纯地要求接口最小化。那么,如果已经满足单一职责原则的接口,在当前的需求下还可以继续细化,那么还需要细化吗?答案是不要再细化了。在实践中,接口设计的粒度越小,系统就越灵活,这是事实。但是灵活的同时也带来了系统的复杂化,导致开发难度增加。所以接口并不是越小越好,必须要有一个度。当单一职责原则和接口隔离原则存在矛盾时,以满足单一职责原则为底线。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,923评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,154评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,775评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,960评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,976评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,972评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,893评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,709评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,159评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,400评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,552评论 1 346
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,265评论 5 341
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,876评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,528评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,701评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,552评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,451评论 2 352