SOLID原则是一个有机整体 - Kislay


SOLID原则是建立一个组件间低耦合度的系统的有力工具。

首先对这些原则做一个简单的回顾:

  • SRP:单一责任原则
  • OCP:开放封闭原则
  • Liskov替代原则
  • 接口隔离
  • 依赖性反转

在这里,我想谈谈所有的SOLID原则是如何相互联系的。
它们在任何情况下都同时适用;破坏一个也会破坏其他多个。
在我看来,它们应该被理解为一个连续体,而不是一套独立的原则:一个人总是需要其中的一些原则来实现另一个(几个)。

就个人而言,我一开始就说我不想修改现有的代码。谁知道我怎么会破坏它?
我只想把我的新逻辑注入到当前运行的系统中,在我需要的特定地方。
所以SRP是我最喜欢的原则。但所有其他的原则都是为了维护这个原则。

以WindowsMachine的例子。下面是这个类,供参考。


public class WindowsMachine {
    private CPU cpu;
    private Monitor monitor;
    private KeyBoard keyboard;

    public WindowsMachine() {
        cpu = new CPU(・・・・); 
        monitor = new Monitor(...);
        keyboard = new Keyboard(..);
    
    public void startUp() {
        cpu.start();
        monitor.start();
      ....
}
}


上述代码表示:WindowsMachine有一个键盘、一个CPU和一个显示器Monitor等子对象。(不懂”类或对象“概念的可见这个链接
在这个例子中,WindowsMachine有创建自己的子对象职责(构造函数中创建了子对象):它不仅需要知道它如何完成自己的功能,还需要知道如何创建这些子组件,这就打破了SRP。(WindowsMachine有了两个职责,而不是一个职责,既要创建照顾组内队员的创建,在构造函数创建队员;还要完成自己本分的职责功能,本职工作是startup函数的功能。)

我们怎样才能从WindowsMachine上移走构建Monitor等子组件的知识呢?
最简单的方法是让别人来构建Monitor对象,并在构建后把它交给WindowsMachine类(就像现实世界中发生的那样)。
这就是依赖性倒置原则,这又是一个SOLID原则。

但是,如果任何人都可以构造一个Monitor并将其传递给WindowsMachine,那么WindowsMachine就需要确保该Monitor与自身的Monitor类型兼容;否则,WindowsMachine就必须处理各种类型的Monitor之间的差异。这又违反了SRP。
WindowsMachine希望其他人创建Monitor,但是所有Monitor都必须准确地做WindowsMachine所期望的事情,不管他们具体如何做到的。

我们怎样才能做到呢?

使用Liskov替代原则,它要求子类完全这样做。

WindowsMachine类暴露了一些接口或基类,包括Monitor的 "规格"。每个Monitor都必须完全做到这一点,而不是其他。这就保证了WindowsMachine可以被赋予任何基类Monitor的实现来工作,而WindowsMachine代码中没有任何东西需要改变。

这里我们再次看到一个原则如何支持另一个原则。

在WindowsMachine的行为受监控器的行为控制的程度上,我们已经实现了OCP,因为我们可以通过不同的Monitor实现,以不同的方式做同样的事情。
但是,我们怎样才能修改WindowsMachine本身的行为呢?
一种方法是打开WindowsMachine的代码,在那里添加一些条件或额外的业务逻辑来满足我们的新要求。
但如果我们这样做,最终在某种程度上违反了SRP,因为它现在因为多种行为原因而被改变。

为了防止这种情况,我们必须重新设计WindowsMachine组件,允许其他人对它进行子类化,并用新的行为覆盖它。
旧的代码仍然适用于现有的用例,但现在可以围绕它构建包装器,以支持新的用例。
在这里,OCP正在帮助维护SRP的长远发展。

让我们来看Monitor显示器本身:
在孤立的情况下,它们可以有很多很多的属性。显示器制造商要处理大量的复杂性:但所有这些都与WindowsMachine无关。
因此,显示器的面向WindowsMachine的部分实现了比面向制造的部分窄得多的规范集。
这就是接口隔离原则
Monito对象为两个不同的用例实现了两套不同的接口。(banq:也就是为不同上下文实现不同接口)

正如这个例子所显示的,SOLID原则不能一个一个地应用。它们必须同时应用,以实现我们在系统中想要的解耦。

banq:WindowsMachine其实类似DDD中的聚合根案例,聚合根的高聚合低耦合实现可以依据此思路