【设计模式笔记03】:里氏代换原则和依赖倒置原则
文章目录
- 三、 里氏代换原则 (LSP)
- 1. 定义
- 2. 历史渊源
- 3. 作用与意义
- 四、 依赖倒置原则 (DIP)
- 1. 定义
- 2. 模块层次理解
- 3. 遵循DIP的设计
- 4. 对定义的深入理解
三、 里氏代换原则 (LSP)
1. 定义
- 核心思想: 一个软件实体如果使用的是一个父类的话,那么一定适用于其子类,而且它察觉不出父类对象和子类对象的区别。
- 通俗解释: 在软件里面,把父类都替换成它的子类,程序的行为没有变化。任何基类可以出现的地方,子类一定可以出现。
- 简单概括: 子类型必须能够替换掉它们的父类型。
2. 历史渊源
- 里氏代换原则由 Barbara Liskov 于1988年提出。
- Barbara Liskov 是2008年图灵奖得主,美国第一位计算机科学女博士,麻省理工学院教授。
3. 作用与意义
- 正是因为有了这个原则,继承复用才成为了可能。
- 只有当子类可以替换掉父类,且软件的功能不受影响时,父类才能真正被复用,而子类也能够在父类的基础上增加新的行为。
- 子类型的可替换性才使得父类型的模块在无需修改的情况下就可以扩展。例如,系统中原来使用
猫对象,现在可以增加狗、猪、牛、羊等动物子类,而使用动物父类型的代码模块不需要任何改变。

由于子类型的可替换性才使得父类型的模块在无需修改的情况下就可以扩展

四、 依赖倒置原则 (DIP)
1. 定义
- 核心思想: 高层模块不应该依赖低层模块,它们都应该依赖抽象。抽象不应该依赖于细节,细节应该依赖于抽象。
- 另一种表述: 要针对接口编程,不要针对实现编程。 (Program to an interface, not an implementation.)
2. 模块层次理解
- 低层模块: 不可分割的原子逻辑,例如一些基础的类或方法。
- 高层模块: 对低层模块进行组合和调用的复杂逻辑。
- 传统依赖关系 (违反DIP): 高层模块直接依赖(调用)低层模块。这种设计下,一旦低层模块发生变化,高层模块也必须随之修改,系统非常不稳定。

3. 遵循DIP的设计
- 引入抽象层: 在高层模块和低层模块之间增加一个抽象层(通常是接口或抽象类)。
- 倒置依赖关系:
- 高层模块依赖于抽象层。
- 低层模块也依赖于(实现或继承)抽象层。
- 这样,高层模块与低层模块之间就不再有直接的依赖关系,它们之间的依赖关系通过抽象层来“倒置”了。

如图展示了正确的依赖关系。高层模块依赖于中间的抽象层,而低层模块也依赖于(实现)抽象层。高层与低层之间通过抽象层解耦。
4. 对定义的深入理解
-
“抽象不应该依赖于细节,细节应该依赖于抽象”:
- 抽象 (接口或抽象类): 是相对稳定的,不应该直接依赖于可能经常变化的具体实现(细节)。
- 细节 (具体实现类): 应该去实现(或继承)抽象,遵循抽象定义的规范。
- 代码层面:
接口或抽象类不能直接new实例化;细节(实现类)可以直接new实例化。 - 依赖抽象暗示着多种对象的可能性(多态)。
- 依赖细节暗示着单一对象,缺乏灵活性。
-
“要针对接口编程,不要针对实现编程”:
- 这句话是依赖倒置原则的最佳实践。
- 在程序代码中,我们定义的变量、方法参数、返回值类型等,应尽量使用接口或抽象类,而不是具体的实现类。
- 这样做的好处是,当我们需要更换具体实现时,只需更换
new一个新实现类的部分,而调用方的代码完全不需要改动,从而实现了对开闭原则的支持。
