• SRP
    一个类的变化来源应该是单一的
  • OCP
    不要随意修改一个类
  • LSP
    设计好类的继承关系。

我们强调面向接口编程,想实现OCP或DIP,都要依赖于接口实现。

接口不就是一个语法吗?把需要的方法都放到接口里面,接口不就出来了吗?
这种对于接口的理解,还只停留在语法层面。设计出来的只能算作是有了个接口,但想要设计出好接口,还要有在设计维度上的思考。

那什么样的接口算是一个好接口呢?这就需要我们了解接口隔离原则。

接口隔离原则

接口隔离原则,Interface segregation principle,ISP:不应强迫使用者依赖于它们不用的方法。
No client should be forced to depend on methods it does not use.

在接口中,不要放置使用者用不到的方法:

  • 站在使用度,这太合理了,我怎么可能爱上我不需要的方法呢?

  • 作为设计者,你肯定也同意

但实际设计时,却不见得都能记得了。

很多人分不清使用者,设计者是不同角色。很多人看来,接口的设计和使用是由同一人完成。这种角色区分意识的缺失,导致我们不能区分两种不同角色,这实质上也是没做好分离关注点。实际开发中,很多人其实两种角色都没有,他们根本没思考过接口的问题,因为他们更关心的是一个个具体类。只有到了必须的时候,接口才作为语法选项使用一次,这种做法干脆就是没思考设计。

然而,你不设计接口,并不代表没有接口。

在做软件设计的时候,我们经常考虑的是模型之间如何交互,接口只是一个方便描述的词汇,为了让我们把注意力从具体的实现细节中抽离出来。但是,如果没有设计特定的接口,你的一个个具体类就变成它的接口。同设计不好的接口一样,这样的“接口”往往也是存在问题的。

那接口设计不好会有什么问题呢?典型的问题就是接口过“胖”,什么叫接口过“胖”呢?我给你举个例子。

胖接口减肥

某银行的系统,支持存款、取款和转账。
通过一个接口向外部系统暴露这些能力,而不同能力的差异要通过请求内容区分。

所以,设计了一个表示业务请求的对象,像下面这样:

每种操作类型都对应着一个业务处理的模块,它们会根据自己的需要,去获取所需的信息,像下面这样:

收到请求后,业务分发即可:

看起来都很好,不少人也写得出来。
然而,在这个实现里,有一个接口就太“胖”了,它就是TransactionRequest。

TransactionRequest这个类包含了相关请求内容,虽无可厚非。但这里,我们容易直觉把它作为参数传给TransactionHandler。
于是,它作为一个请求对象,摇身一变,成了业务处理接口的一部分。

虽然你没有设计特定的接口,但具体类可以变成接口。不过,作为业务处理中的接口,TransactionRequest就显得“胖”了:

getDepositAmount方法只在DepositHandler 里使用;
getWithdrawAmount方法只在WithdrawHandler里使用;
getTransferAmount只在TransferHandler使用。
然而,传给它们的TransactionRequest却包含所有这些方法。

这有什么问题吗?
问题就在于,一个“胖”接口常常是不稳定的。比如说,现在要增加一个生活缴费的功能,TransactionRequest就要增加一个获取生活缴费金额的方法:

相应还需增加业务处理的方法:

虽然这种做法看上去还挺OCP,但实际上,由于TransactionRequest的修改,前面几个写好的业务处理类:DepositHandler、WithdrawHandler、TransferHandler都会受到影响。为什么这么说呢?

如果我们用的是一些现代的程序设计语言,你的感觉可能不明显。假如这段代码是用C/C++这些需要编译链接的语言写成的,TransactionRequest的修改势必会导致其它几个业务处理类重新编译,因为它们都引用了TransactionRequest。

实际上,C/C++的程序在编译链接上常常需要花很多时间,除了语言本身的特点之外,因为设计没做好,造成本来不需要重新编译的文件也要重新编译的现象几乎是随处可见的。

可理解为,如果一个接口修改了,依赖它的所有代码全部会受到影响,而这些代码往往也有依赖于它们实现的代码,这样一来,一个修改的影响就传播出去了。用这种角度去评估,你就会发现,不稳定的“胖”接口影响面太广。

怎样修改这段代码呢?既然这个接口是由于“胖”造成的,给它减肥就好了。根据ISP,只给每个使用者提供它们关心的方法。所以,我们可以引入一些“瘦”接口:

这里,把TransactionRequest变成了一个接口,目的是给后面的业务处理进行统一接口,而ActualTransactionRequest则对应着原来的实现类。我们引入了DepositRequest、WithdrawRequest、TransferRequest等几个“瘦”接口,它们就是分别供不同的业务处理方法使用的接口。

有了这个基础,我们也可以改造对应的业务处理方法了:

经过这个改造,每个业务处理方法就只关心自己相关的业务请求。那么,新增生活缴费该如何处理呢?你可能已经很清楚了,就是再增加一个新的接口:

然后,再增加一个新的业务处理方法:

对比两个设计,只有ActualTransactionRequest做了修改,而因为这个类表示的是实际的请求对象,在现在的结构之下,它是无论如何都要修改的。而其他的部分因为不存在依赖关系,所以,并不会受到这次需求增加的影响。相对于原来的做法,新设计改动的影响面变得更小了。

你的角色

回顾设计改进过程,重点在于,原本那个大的TransactionRequest被拆成若干小接口,每个小接口就只为特定的使用者服务。
好处在于,每个使用者只要关注自己所使用的方法,这样接口才可能稳定,“胖”接口不稳定的原因就是,它承担了太多的职责。

或许你从这个讨论里听出了一点SRP的味道,没错,你甚至可以把ISP理解成接口设计的 SRP。

ActualTransactionRequest实现了多个接口。在这个设计里面,每个接口代表着与不同使用者交互的角色,Martin Fowler将这种接口称为角色接口(Role Interface)。
就像每个人在实际生活中扮演着不同的角色。
在家里,我们是父母的子女
在公司里,我们是公司的员工
购物时,我们是顾客
出行时,我们是乘客。
但所有这些角色最终都是由我们一个人承担的。前面讲做接口设计时,我们虽然是一个个体,但常常要同时扮演设计者和使用者两个不同的角色。而在这段代码里,各种角色则汇聚到了ActualTransactionRequest。

在一个设计中,识别出不同角色至关重要,分离关注点!

接口是把变和不变隔离开。现在有ISP,接口应该是尽可能稳定。接口的使用者对于接口是一种依赖关系,被依赖的一方越稳定越好,而只有规模越小,才越有可能稳定。

还可从更广泛角度理解ISP,不依赖于任何不需要的东西。

之所以会依赖于这个数据库,是因为在技术选型时,我们用到了一个特定的框架,而这个框架缺省就依赖于这个数据库。开发人员为了快速实现,就把框架和数据库一起引入到了项目中,引发了后面的这些问题。

在高层次上依赖于不需要的东西,这和类依赖于不需要的东西异曲同工。

总结

不应强迫使用者依赖于它们不需要的方法。因为很多接口都设计得包含了太多内容。更好的设计是把大接口分解成一个个小接口。

这里的接口不仅是一种语法,所有的public方法都是接口。

我们在做接口设计时,需要关注不同的使用者。我们可以把ISP理解成接口设计的SRP。每个使用者面对的接口,其实都是一种角色接口。识别出接口不同的角色是至关重要的,这也与分离关注点的能力是相关的。

ISP还可以从更广泛的角度去理解,也就是说,不要依赖于任何不需要的东西,这个原则可以指导我们在高层次上进行设计。

除了接口太“胖”造成的问题,还有一个很重要的问题,它的依赖方向搞反了。我们下一讲就来讨论到底谁该依赖谁的设计原则:依赖倒置原则。

识别对象的不同角色,设计小接口。

接口隔离原则:接口里的方法,你都用得到吗?相关推荐

  1. 【专题系列】设计模式—— 四:接口隔离原则

    点击上方"java大数据修炼之道",选择"设为星标" 优质文章, 第一时间送达 来源 | https://www.cnblogs.com/three-fight ...

  2. 面象对象设计6大原则之四:接口隔离原则

    转载自 面象对象设计6大原则之四:接口隔离原则 接口隔离原则(ISP),The Interface Segregation Principle 定义 客户端不需要强迫依赖那些它们不需要的接口. 类与接 ...

  3. 设计模式—— 四:接口隔离原则

    什么是接口隔离原则? 接口隔离原则有两种定义: Clients should not be forced to depend upon interfaces that they don't use.( ...

  4. Java设计模式七大原则-接口隔离原则

    接口隔离原则(Interface Segregation Principle) 基本介绍 1) 客户端不应该依赖它不需要的接口,即一个类对另一个类的依赖应该建立在最小的接口上 2) 先看一张图: 类A ...

  5. 设计模式系列(二)七大设计原则-----接口隔离原则

    七大设计原则之单一接口隔离原则 接口隔离原则 案例 应用实例 改进 上一篇:设计模式系列(一)七大设计原则-----单一职责原则 下一篇:设计模式系列(三)七大设计原则-----依赖倒转原则 接口隔离 ...

  6. 【软件架构设计原则】单一职责原则和接口隔离原则

    文章目录 软件架构设计原则 单一职责原则 接口隔离原则 其他设计原则 软件架构设计原则 本文通过实例来讲解 单一职责原则 接口隔离原则 单一职责原则 单一职责(Simple Responsibilit ...

  7. 五、设计模式——接口隔离原则

    接口隔离原则 接口隔离原则:客户端不应该被迫依赖于它不使用的方法(要为各个类建立它们需要的专用接口,而不要试图去建立一个很庞大的接口供所有依赖它的类去调用) 接口隔离原则和单一职责都是为了提高类的内聚 ...

  8. 单一职责原则和接口隔离原则区别的理解

    网上对于两者的区别众说纷纭,总是一套理论下来跟没有说一样,下面说说自己的理解:  单一职责原则: 是将某一职责的方法全放在一个接口中,这时候就会出现实现该接口的类必须实现该接口中自己用不到的方法(违背 ...

  9. [设计模式]设计模式之禅关于接口隔离原则

    在讲接口隔离原则之前,先明确一下我们的主角--接口.接口分为两种: ● 实例接口(Object Interface),在Java中声明一个类,然后用new关键字产生一个实例,它是对一个类型的事物的描述 ...

最新文章

  1. ACCP7.0-S2-复习自测-15测试分析
  2. jQuery 选择器 之 案例:淘宝服饰精品案例
  3. 从美图、4399生根,到趣店、瑞幸落户,厦门离中国的西雅图还有多远?
  4. html按键清空怎么写_html的空格代码怎么写?教你如何使用空格nbsp代码
  5. CNN卷积神经网络深度解析
  6. 自定义能够for each的类,C#,Java,C++,C++/cli的实现方法
  7. buck变换器设计matlab_一种用于Boost PFC变换器的改进关断时间控制策略
  8. Java中截取字符串中小数点前面的字符
  9. hashmap扩容_面试官问:HashMap在并发情况下为什么造成死循环?一脸懵
  10. php中的图片变名为8位用什么,CSS_详解PNG图片,1、PNG图片类型 PNG格式有8位、 - phpStudy...
  11. 分享10个最佳Linux VPS服务器托管
  12. 【MYSQL】【基础知识】【mysql联合主键如何 in查询】
  13. 昊海微信拼团php,最新微信昊海拼团系统独立版源码分享,微信团购关注送红包送优惠卷功能,附说明文档...
  14. RabbitMQ集群安装配置+HAproxy+Keepalived高可用
  15. Python多子图绘制
  16. 字符串与16进制之间的转换
  17. 数据库求候选码的算法
  18. 使用AW9523B芯片驱动16路LED时,LED出现误点亮的问题
  19. 液体效果,制作喷溅的液态裙子教程
  20. 万盛酒店餐饮管理系统(SpringBoot,SSM,MySQL )

热门文章

  1. spreadtrum 6600L 开机init流程
  2. 三-五功能/半亮/25%亮/全亮/爆闪/SOS_专用应急灯手电筒IC方案
  3. roc曲线spss怎么做_SPSS单因素ROC曲线及多因素联合诊断ROC曲线绘制(原创手把手) - 医学统计和生物统计讨论版 -丁香园论坛...
  4. 在office如何安装翻译软件插件
  5. Web全栈~06.CSS选择器
  6. DBCA创建数据库实例
  7. 数据中心100G主流应用技术分析
  8. 理解vue-admin-template模板,连接后端改造登陆功能
  9. eclipse因jdk打不开解决
  10. Sentinel @SentinelResource 详解