接口隔离原则背后的原因是什么?
题
接口隔离原则 (ISP) 指出,许多客户端特定接口比一个通用接口更好。为什么这很重要?
解决方案
ISP 声明:
不应强迫客户依靠他们不使用的方法。
ISP涉及到的重要特性—— 凝聚 和 耦合.
理想情况下,您的组件必须是高度定制的。它提高了代码的健壮性和可维护性。
执行 ISP 可为您带来以下好处:
如果您想了解有关软件设计原则的更多信息,请获取 敏捷软件开发、原则、模式和实践 书。
其他提示
界面隔离是 SOLID 原则上的“I”,在深入研究第一个之前,让我们先解释一下后者的含义。
SOLID 可以被认为是专家提出的一组最佳实践和建议(意味着它们之前已经被证明),以便为我们如何设计应用程序提供可靠的基础。这些实践致力于使我们的应用程序更易于维护、扩展、调整和扩展。
我为什么要关心 SOLID 编程?
首先,你必须意识到你不会永远停留在原地。如果我们使用标准和众所周知的架构,我们可以确定我们的代码将很容易被我们之后的其他开发人员维护,并且我确信您不会想要处理修复没有的代码的任务。没有应用任何已知的方法,因为它很难理解。
接口隔离原则。
我们知道 SOLID 原则是什么,我们可以更详细地了解接口隔离原则,但是接口隔离到底说了什么?
“不应强迫客户实施他们不会使用的不必要方法”
这意味着有时我们倾向于使用很多方法来创建接口,这在一定程度上可能是好的,但是这很容易被滥用,并且我们最终可能会得到实现空或无用方法的类,这当然会增加额外的代码和负担到我们的应用程序。想象一下,您在单个接口中声明了很多方法,如果您喜欢视觉辅助,那么一个正在实现接口但实际上需要几个方法的类将如下所示:
另一方面,如果您正确应用接口隔离并将接口拆分为较小的子集,您可以确保实现仅需要的接口:
看!好多了!执行这一原则将使您具有低耦合性,这有助于更好的可维护性和对变化的高抵抗力。因此,您可以在真正需要时真正利用接口的使用并实现方法。现在让我们回顾一个不太抽象的示例,假设您声明了一个名为 Reportable 的接口
public interface Reportable {
void printPDF();
void printWord();
void printExcel();
void printPPT();
void printHTML();
}
而你有一个客户端,只会导出一些Excel格式的数据,你可以实现接口,但你只需要实现excel方法吗?答案是否定的,即使您不打算使用它们,您也必须为所有方法编写实现代码,这可能会导致大量垃圾代码,从而使代码难以维护。
记住保持简单,不要重复自己,你会发现你已经在不知不觉中使用了这个原则。
它简化了任何一个客户端将使用的接口,并消除了他们可能在不需要的接口部分上开发的依赖关系。
原因之一是,拥有许多接口且每个接口的方法数量最少,可以更轻松地实现每个接口并正确实现它们。大的界面可能会不守规矩。此外,在场景中使用集中接口使代码更易于维护,因为您可以看到正在使用对象的哪个方面(例如,IComparable 接口让您知道该对象仅用于给定场景中的比较)。
这一原则主要有两个目的
使代码更具可读性和可管理性。
促进班级的单一责任(高内聚)。当然,为什么一个类应该有一个没有行为影响的方法呢?为什么不直接删除它呢。这就是 ISP 的意义所在
设计人员必须向 ISP 询问几个问题
- 通过 ISP 可以实现什么目标
- 如何分析现有代码是否存在任何 ISP 违规行为
为了进一步讨论,我还必须补充一点,这个原则并不是最严格意义上的“原则”,因为在某些情况下,将 ISP 应用于设计,而不是提高可读性,可能会使对象结构变得不可读并且混乱不必要的代码。您可能会在 java.awt.event 包中观察到这一点
更多内容请见我的博客: http://design-principle-pattern.blogspot.in/2013/12/interface-segregation-principle.html
互联网服务供应商 很重要。
ISP的基本思想:客户端不应该被迫依赖它不使用的方法。
这个原则似乎更符合逻辑。理想情况下,客户端不应实现客户端不使用的方法。
请参阅以下 SE 问题的代码示例:
优点:
灵活性 :如果没有 ISP,您将拥有一个通用 FAT 接口和许多实现它的类。假设您有 1 个接口和 50 个类。如果接口发生变化,所有 50 个类都必须更改其实现。
通过 ISP,您可以将通用 FAT 接口划分为细粒度的小接口。如果小粒度接口发生更改,则只有实现该接口的类才会受到影响。
可维护性和易用性:由于更改仅限于细粒度接口而不是通用 FACT 接口,因此代码维护更容易。不相关的代码不再是实现类的一部分。
当只有一种特定于客户或一种特定于行为的变化时,避免回归工作。如果您将所有行为方法都组合在一个大接口中,那么只需考虑一下您将如何最终测试所有您所引用的代码片段,即使只发生了很小的更改也是如此。
更详细的解释可以参考 接口隔离原理文章
罗伯特·马丁的论文 关于这个主题给出了一个不常被提及的解释:
客户端在接口上施加的向后力。
如果两个类直接依赖于第三个类的两种不同方法,则前两个类中的任何一个的更改影响另一个类的可能性就会增加。
假设我们有三个类: Red
, Green
, , 和 Blue
.
Red
和 Green
两者都依赖 Blue
, ,但每个都取决于不同的方法。这意味着 Red
取决于一种方法 Blue
但不使用其他方法。同样地, Green
依赖于取决于 Blue
, ,但只使用一种方法,而不使用另一种。
违反原则的情况是 Red
和 Green
因为每个都取决于一个类 - Blue
- 但 不 至少使用其中一种方法。
这可能会产生什么问题?
- 我需要改变
Red
, ,我也改变Blue
以满足Red
. - 我没有改变里面的具体方法
Blue
那Green
取决于,但尽管如此,Green
依赖于取决于Blue
我已经改变了Blue
, ,这仍然可能影响Green
. - 因此,我的更改为
Red
有潜力影响Blue
因为他们引导我改变了两个都依赖的类。
那就是“向后部队”。由于客户的需求,我们有时会更改课程。如果该类有不同的客户使用它来做不同的事情,我们就有影响他们的风险。
如上所述,接口隔离原则的简单定义是:
任何客户端都不应被迫依赖于它不使用的方法。
结合这一点和 Robert Martin 论文中的上述观点,很明显,许多对 ISP 的解释实际上是在谈论其他原则。
- 具有大量方法的类或接口是不可取的,但这并不是专门因为 ISP 的原因。他们可能违反单一责任。但 ISP 违规并不在大接口或大类中,而是在类中 取决于 如果他们不使用大接口的所有方法,则在大接口上。如果他们使用所有方法,听起来仍然很混乱,但这与 ISP 无关。
- 实现接口但对某些方法抛出异常的类是不好的,但这也不是 ISP。ISP 是关于类的 依靠 在接口上,而不是在类上 实施 接口。
如果我们谷歌“接口隔离”,大多数包含代码示例的顶级结果都展示了以下类: 不完全执行 接口,这不是 ISP 的重点。有些人甚至重申了这个原则:
接口隔离原则指出,不应强迫客户端实现他们不使用的接口
...但那是 不是 原则。定义文件提到这些担忧是违反 ISP 的副作用,但指出它们是违反里氏替换的。
此外,每次将新接口添加到基类时,必须在派生类中实现(或允许默认)接口。事实上,相关的做法是将这些接口作为 nil 虚函数而不是纯虚函数添加到基类中;特别是这样派生类就不必承担实现它们的负担。正如我们在本专栏的第二篇文章中了解到的,这样的做法 违反了里氏替换原则(LSP),导致维护和可重用性问题。
更重要的是,说客户端不应该实现它不使用的方法甚至没有意义。这 客户 接口的方法不实现它的方法。
我并不是要夸大地引用这篇论文,就好像它是圣书或其他什么东西一样。但是,如果我们要使用文章中描述的原理的名称(文章本身的名称),那么我们还应该考虑该文章中包含的实际定义和解释。