SOLID “接口隔离原则”与“单一职责原则”有何不同?
SOLID的维基百科条目说
ISP 将非常大的接口拆分为更小、更具体的接口,以便客户端只需了解他们感兴趣的方法
然而,对我来说,这听起来就像只是将 SRP 应用于接口和类。毕竟,如果一个接口只负责一个概念上的事情,那么您将无法进一步分解它。
我错过了什么,还是 ISP 与 SRP 有点多余?如果不是,那么 ISP 暗示 SRP 没有什么?
SRP 告诉我们,您应该在一个模块中只承担单一职责。
ISP 告诉我们,您不应该被迫面对超出您实际需要的东西。如果您想使用print()
interface 中的方法I
,则不必为此实例化 aSwimmingPool
或DriveThru
类。
更具体地说,直截了当,它们是对同一想法的不同看法——SRP 更关注设计者的观点,而 ISP 更关注客户端的观点. 所以你基本上是对的。
这一切都来自
ISP 最初是由 Robert C. Martin 在为 Xerox 做一些咨询时使用和制定的。施乐创建了一个新的打印机系统,可以执行各种任务,例如装订一组打印的文件和传真。该系统的软件是从头开始创建并成功执行其任务的。随着软件的发展,修改变得越来越困难,以至于即使是最小的更改也需要重新部署周期到一个小时。这使得继续开发几乎不可能。设计问题是几乎所有任务都使用一个主要的 Job 类。每当必须完成打印作业或装订作业时,都会调用 Job 类中的某个方法。这导致了一个巨大的或“胖”类,其中包含多种特定于各种不同客户端的方法。
所以
Martin 提出的解决方案就是今天所谓的接口隔离原则。应用于 Xerox 软件,使用依赖倒置原则在 Job 类与其所有客户端之间添加了一层接口。没有一个大的 Job 类,而是创建了 Staple Job 接口或 Print Job 接口,分别由 Staple 或 Print 类使用,调用 Job 类的方法。因此,为每个作业创建了一个接口,这些接口都是由 Job 类实现的。
@ http://en.wikipedia.org/wiki/Interface_segregation_principle#Origin
SRP 关注模块做什么以及如何完成,不允许任何抽象级别的混合。基本上,只要一个组件可以用一个句子广泛定义,它就不会破坏 SRP。
另一方面,ISP 关心应该如何使用模块,是否只使用模块的一部分,而忽略某些方面是否有意义。
保持精神或 SRP 但可以破坏 ISP 的代码示例是外观模式。它有一个单一的职责,“提供对更大子系统的简化访问”,但如果底层子系统需要公开截然不同的想法,它确实会破坏 ISP。
也就是说,通常当一段代码破坏了 SOLID 原则时,它通常会破坏整个代码。打破特定原则而保留其余原则的具体例子在野外很少见。
罗伯特·马丁于 2018 年 5 月 16 日发布了以下推文。
对于接口,ISP 可以看作类似于 SRP;但不仅如此。ISP 概括为:“不要依赖于你需要的东西。” SRP 概括为“将因相同原因在同一时间发生变化的事物聚集在一起。”</p>
想象一个同时具有 push 和 pop 的堆栈类。想象一个只会推送的客户端。如果该客户端依赖于堆栈接口,它依赖于它不需要的 pop。SRP 不会将 push 与 pop 分开;ISP 会。