设计模式之美
王争
前Google工程师,《数据结构与算法之美》专栏作者
立即订阅
17679 人已学习
课程目录
已更新 21 讲 / 共 100 讲
0/6登录后,你可以任选6讲全文学习。
开篇词 (1讲)
开篇词 | 一对一的设计与编码集训,让你告别没有成长的烂代码!
免费
设计模式学习导读 (3讲)
01 | 为什么说每个程序员都要尽早地学习并掌握设计模式相关知识?
02 | 从哪些维度评判代码质量的好坏?如何具备写出高质量代码的能力?
03 | 面向对象、设计原则、设计模式、编程规范、重构,这五者有何关系?
设计原则与思想:面向对象 (11讲)
04 | 理论一:当谈论面向对象的时候,我们到底在谈论什么?
05 | 理论二:封装、抽象、继承、多态分别可以解决哪些编程问题?
06 | 理论三:面向对象相比面向过程有哪些优势?面向过程真的过时了吗?
07 | 理论四:哪些代码设计看似是面向对象,实际是面向过程的?
08 | 理论五:接口vs抽象类的区别?如何用普通的类模拟抽象类和接口?
09 | 理论六:为什么基于接口而非实现编程?有必要为每个类都定义接口吗?
10 | 理论七:为何说要多用组合少用继承?如何决定该用组合还是继承?
11 | 实战一(上):业务开发常用的基于贫血模型的MVC架构违背OOP吗?
12 | 实战一(下):如何利用基于充血模型的DDD开发一个虚拟钱包系统?
13 | 实战二(上):如何对接口鉴权这样一个功能开发做面向对象分析?
14 | 实战二(下):如何利用面向对象设计和编程开发接口鉴权功能?
设计原则与思想:设计原则 (4讲)
15 | 理论一:对于单一职责原则,如何判定某个类的职责是否够“单一”?
16 | 理论二:如何做到“对扩展开放、修改关闭”?扩展和修改各指什么?
17 | 理论三:里式替换(LSP)跟多态有何区别?哪些代码违背了LSP?
18 | 理论四:接口隔离原则有哪三种应用?原则中的“接口”该如何理解?
不定期加餐 (2讲)
加餐一 | 用一篇文章带你了解专栏中用到的所有Java语法
加餐二 | 设计模式、重构、编程规范等相关书籍推荐
设计模式之美
登录|注册

18 | 理论四:接口隔离原则有哪三种应用?原则中的“接口”该如何理解?

王争 2019-12-13
上几节课中,我们学习了 SOLID 原则中的单一职责原则、开闭原则和里式替换原则,今天我们学习第四个原则,接口隔离原则。它对应 SOLID 中的英文字母“I”。对于这个原则,最关键就是理解其中“接口”的含义。那针对“接口”,不同的理解方式,对应在原则上也有不同的解读方式。除此之外,接口隔离原则跟我们之前讲到的单一职责原则还有点儿类似,所以今天我也会具体讲一下它们之间的区别和联系。
话不多说,现在就让我们正式开始今天的学习吧!

如何理解“接口隔离原则”?

接口隔离原则的英文翻译是“ Interface Segregation Principle”,缩写为 ISP。Robert Martin 在 SOLID 原则中是这样定义它的:“Clients should not be forced to depend upon interfaces that they do not use。”直译成中文的话就是:客户端不应该强迫依赖它不需要的接口。其中的“客户端”,可以理解为接口的调用者或者使用者。
实际上,“接口”这个名词可以用在很多场合中。生活中我们可以用它来指插座接口等。在软件开发中,我们既可以把它看作一组抽象的约定,也可以具体指系统与系统之间的 API 接口,还可以特指面向对象编程语言中的接口等。
取消
完成
0/1000字
划线
笔记
复制
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
该试读文章来自付费专栏《设计模式之美》,如需阅读全部文章,
请订阅文章所属专栏。
立即订阅
登录 后留言

精选留言(45)

  • 辣么大
    Java.util.concurrent.atomic包下提供了机器底层级别实现的多线程环境下原子操作,相比自己实现类似的功能更加高效。
    AtomicInteger提供了
    intValue() 获取当前值
    incrementAndGet() 相当于++i
    getAndIncrement相当于i++
    从getAndIncrement实现“原子”操作的角度上来说,原子级别的给整数加一,返回未加一之前的值。它的职责是明确的,是符合单一职责的。

    从接口隔离原则上看,也是符合的,因为AtomicInteger封装了原子级别的整数操作。

    补充:
    多线程环境下如果需要计数的话不需旧的值时,推荐使用LongAdder或者LongAccumulator(CoreJava上说更加高效,但我对比了AtomicLong和LongAdder,没感觉效率上有提高,可能是例子写的不够准确。测试代码见 https://github.com/gdhucoder/Algorithms4/tree/master/designpattern/u18 希望和小伙伴们一起讨论)
    2019-12-13
    2
    16
  • NoAsk
    单一职责原则针对的是模块、类、接口的设计。getAnd
    Increase()虽然集合了获取和增加两个功能,但是它作为对atomicInteger的值的常用方法,提供对其值的常规操作,是满足单一原则的。

    从单一原则的下面这个解释考虑,是不满足接口隔离原则的。“如果调用者只使用部分接口或接口的部分功能,那接口的设计就不够职责单一。”,用户可能调用获取或增加的其中一个方法,再或者先调用增加再调用获取increaseAndGet()方法。

    这是我个人理解,还望大家指正。
    2019-12-13
    1
    10
  • 时光流逝,而我们在干嘛?
    老师可以每次课对上一次课的思考题做下解答吗

    作者回复: 集中答疑一下吧 课都提前录好了

    2019-12-13
    6
  • 李小四
    设计模式_18
    纯理论分析,这么设计是不符合“接口隔离”原则的,毕竟,get是一个操作,increment是另一个操作。

    结合具体场景,Atomic类的设计目的是保证操作的原子性,专门看了一下AtomicInteger的源码,发现没有单独的 increment 方法,然后思考了一下线程同步时的问题,场景需要保证 get 与 increment 中间不插入其他操作,否则函数的正确性无法保证,从场景的角度,它又是符合原则的。
    2019-12-13
    2
    4
  • 北岛明月🍃
    符合SRP 也符合ISP 。

    理由是这个方法完成的逻辑就是一个功能:新增和返回旧值。只不过是两步操作罢了。如果你想获取,就用get方法,自增就用increment 方法。都有提供哇。

    SRP:老师在文中说,实际上,要从中做出选择,我们不能脱离具体的应用场景。所以我认为是符合的。

    ISP: 可以参考老师说的这句话:而接口隔离原则相对于单一职责原则,一方面它更侧重于接口的设计,另一方面它的思考的角度不同。它提供了一种判断接口是否职责单一的标准:通过调用者如何使用接口来间接地判定。如果调用者只使用部分接口或接口的部分功能,那接口的设计就不够职责单一。
    我们调用这个方法肯定是要用它的整个功能,而不是其中的一个新增或自增功能。
    2019-12-13
    4
  • 墨雨
    单一职责是针对于模块、类在具体的需求业务场景下是否符合只做一件事情的原则。
    而接口隔离原则就细化到了接口方面,我是这样理解的,如果接口中的某些方法对于需要继承实现它的类来说是多余的,那么这个接口的设计就不符合接口隔离原则,可以考虑再拆分细化。
    对于课后思考题,他只对该数做了相关操作符合单一职责原则。但从接口、函数来看它实现了两个功能,获取整数及给该整数加一,是不符合接口隔离原则的。
    不知道我这样考虑是否正确,望指正
    2019-12-13
    1
    3
  • 小晏子
    思考题:
    先看是否符合单一职责原则,这个函数的功能是加1然后返回之前的值,做了两件事,是不符合单一职责原则的!
    但是却符合接口隔离原则,从调用者的角度来看的话,因为这个类是Atomic类,需要的所有操作都是原子的,所以为了满足调用者需要原子性的完成加一返回的操作,提供一个这样的接口是必要的,满足接口隔离原则。
    2019-12-13
    2
  • 下雨天
    老师提到三种接口的情况可以这样理解:
    1. 接口定义前设计原则(理解成OOP中语法接口或未定义的函数):尽量单一,细粒度!

    2.接口定义后设计原则(理解成粗粒度的一组集合或函数):已有接口按需(调用者或者新功能)拆分或单独定义接口!
    2019-12-13
    1
  • 黄林晴
    思考题:
    个人感觉,不符合单一职责,也不符合接口隔离,因为函数做了两件事,不应该把获取当前值和值加1放在一起,因为
    1.用户可能需要-1 *1等其他运算操作再返回原始值,这样就要n个方法每个方法中都有返回原始值的操作。
    2.用户可能只想运算操作,不想运算后暴露原始结果
    3.如果用户以后还想获取操作后的值,这个函数就不能同时返回两个值了
    希望大家指正
    2019-12-13
    1
  • Chen
    getAndIncrement()符合接口隔离原则,这是不是一个大而全的函数,而是一个细粒度的函数,跟count++的功能类似。
    2019-12-13
    1
  • javaadu
    这个接口放在Java并发编程这个场景下,符合单一职责原则—就是为了实现某个数得自增,同时解决了并发情况下数据覆盖的问题。

    这个接口从接口隔离的角度,不符合接口隔离原则,因为该接口实现了get和increment两个功能,但是有可能调用者只需要其中一个
    2019-12-15
  • Liam
    从命名来看,它就是要实现get&increment,功能明确,符合单一职责;从使用场景来看,如果你只是想get或increment,它就违背了接口分离,因为引入了不需要的功能;但是如果调用者本来就需要get&increment,那么它是没有违背接口分离的;
    2019-12-15
  • 白彬
    从原子操作的功能需求上考虑需要一个原子的操作支持返回老值和对计数器加一的原子操作。这个api是符合单一职责和接口隔离原则的。
    2019-12-14
  • 白彬
    我理解符合单一原则。符合接口隔离原则。
    从功能上讲 返回老值对原有值加一就是一个原子变量的基本功能。
    从接口隔离讲。本身一个函数不涉及多个接口组合,用户依赖其中一个不依赖另一个的问题。而且这个函数不涉及返回多个数据,用户依赖其中一个属性的问题,用户调用说明需要这个函数的全部功能。
    2019-12-14
  • DullBird
    感觉是属于比较难判断是否单一职责的内容,顺便回头翻了一下单一职责的章节:在理解一下,单一职责主要还是要结合业务,getAndIncrement的方法实现了: 原子的获取并且新增的这一职责,如果拆开成get和Increment的话,就需要外层加锁处理原子的获取并新增操作,对于业务不太合适。
    从接口隔离的原则看,调用这个方法的类,本身就是依赖这个接口,所以并没有违反。
    想到一个问题:
    如果一个类中,有n个查询的业务接口,根据姓名查,根据年纪查,根据地址查(假设不是参数控制,而是拆成3个接口)。那么不同调用方依赖这个类的时候,有可能是根据姓名查,有可能根据年纪查,如果都拆开了。那么接口是不是粒度太细了
    2019-12-14
  • 小海
    回答课后讨论题得结合具体的场景和运行环境。AtomicInteger的getAndIncrement()函数的职责很单一,就是"获取当前值并递增"这一步原子操作,有人说这是两步操作,这个函数是运行在多线程并发环境下,在这种环境下把获取当前值和递增拆分成两个函数会获得错误的结果,而该函数内部封装了两步操作使其成为一个原子操作,从这个角度任意一方都是另一方的附属品,两者必须同时完成而不能拆分,如果仅仅是为了获取当前值或者递增那完全可以使用该类的其它函数。从调用方的角度,必然是同时用到了获取当前值和递增两个功能,而不是部分功能,明白该函数设计的"单一职责",就知道它符合SRP和ISP,不要试图去拆分一个原子操作。
    2019-12-14
  • 筱乐乐哦
    我个人理解是两个都满足
    理由如下(个人观点):
    1、除了文章中提到的getAndIncrement,它里面还有getAndDecrement、incrementAndGet、decrementAndGet等这这种方法,操作的核心目的肯定是在于对于变量的加减操作,返回的值就是加减前后的,单一职责的我感觉满足了,如果目的不是为了加减,那就直接调用个get方法就好
    2、对于1中说到的4个方法,例如getAndIncrement,incrementAndGet同样是加1,一个返回加之前一个加后,对于使用者,假如我就是要加之前的,那么也是完全符合接口隔离原则的,如果就是increment了,肯定有人在调用的时候,需要要加之前或者加之后的,自己还要在get一次
    2019-12-13
  • 阿冰777
    我觉得应该是并发包,直接操作内存,对于锁的机制比较严格,所以将读和写操作写在一起,方便锁的处理吧.猜测而已,主写前端,对并发和锁不太懂.
    2019-12-13
  •  扬帆丶启航 
    个人认为是满足单一原则的,因为只做了整数加一的操作;但是不满足接口隔离原则,因为不仅实现了整数加一,还提供了返回加一前的整数,调用者可能只使用其中的一个功能。
    2019-12-13
  • Miaozhe
    这种方法中既有逻辑(新增,修改和删除逻辑),又要返回不是操作结果的内容,的确有二意性,项目中为了减少宂余,确实有这样的场景。
    个人认为把 方法的操作和返回值,在方法名称中清晰的体现出来,名称和实际实现一致。

    回到老师的题目,getAndIncrement方法名称,体现了:
    1.increment 自增
    2.get 返回
    同时有And说明是2个操作。
    2019-12-13
    1
收起评论
45
返回
顶部