diff --git a/README.md b/README.md index be07996..19b453f 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,7 @@ https://datawhalechina.github.io/sweetalk-design-pattern/#/ | | 开闭原则 | 长琴 | | | 依赖倒置原则 | 胡锐锋 | | | 迪米特原则 | 碧涵 | +| | 里氏替换原则 | 长琴 | | 设计模式 | 简单工厂模式、策略模式、装饰模式、代理模式、工厂方法模式 | 肖桐 | | | 原型模式、模板方法模式、外观模式、建造者模式 | 碧涵 | | | 观察者模式、抽象工厂模式、状态模式、适配器模式 | 长琴 | @@ -85,6 +86,7 @@ README.md------------------------------------------项目说明 ### ChangeLog +- v1.2完成初版 221023 - v1.1完成笔记 221008 - v1.0基础结构 220916 diff --git a/docs/content/design_principles/README.md b/docs/content/design_principles/README.md index f29f1dc..884b677 100644 --- a/docs/content/design_principles/README.md +++ b/docs/content/design_principles/README.md @@ -1,15 +1,15 @@ # 设计原则 -本部分介绍设计原则,书中一共提到四个原则: +本部分介绍设计原则,书中一共提到以下几个原则: - 单一职责原则(Single Responsibility Principle,SRP):修改一个类的原因只有一个。 - 开闭原则(Open-Closed Principle,OCP):对于扩展类应该开放,对于修改类应该封闭。 - 迪米特法则(Law of Demeter,LoD):也叫最少知识原则,类应尽量降低成员的访问权限,即耦合尽可能弱。 - 依赖倒置原则(Dependency Inversion Principle,DIP):高层次的类不应依赖低层次的类,都应依赖于抽象接口。 +- 里氏替换原则(Liskov Substituion Principle,LSP):扩展一个类时,能够(不修改代码)将子类的对象作为父类对象进行传递。和依赖倒置原则意思接近。 此外,还有下面常见的设计原则: -- 里氏替换原则(Liskov Substituion Principle,LSP):扩展一个类时,能够(不修改代码)将子类的对象作为父类对象进行传递。和依赖倒置原则意思接近。 - 接口隔离原则(Interface Segregation Principle,ISP):尽量缩小接口范围,让客户端不必实现不用的方法。和迪米特法则接近。 - 合成/聚合复用原则(Composite/Aggragate Reuse Principle,CARP):尽量通过合成/聚合而不是继承达到复用目的。 diff --git a/docs/content/design_principles/dependence_inversion_principle.md b/docs/content/design_principles/dependence_inversion_principle.md index d0c9d29..d631399 100644 --- a/docs/content/design_principles/dependence_inversion_principle.md +++ b/docs/content/design_principles/dependence_inversion_principle.md @@ -1,12 +1,27 @@ # 依赖倒置原则 -## 1 概念 +依赖倒置原则,Dependence Inversion Principle,简称 DIP,是指程序不应该依赖细节,细节应该依赖于抽象。简单来说,就是要针对接口编程,不要针对实现编程。 -  依赖倒置原则(Dependence Inversion Principle, DIP)是程序不应该依赖细节,细节应该依赖于抽象。简单来说,就是要针对接口编程,不要针对实现编程。 +**使用动机** -## 2 知识点 +面对不同的具体实现做到易拔插,松耦合。 -- 高层模块不应该依赖低层模块,两个都应该依赖抽象 -- 抽象不应该依赖细节,细节应该依赖抽象 -- 依赖倒置的中心思想是面向接口编程 -- 使用接口或抽象类的目的是制定好规范,不涉及任何具体的操作,把展现细节的任务交给实现类去完成 +**如何使用** + +- 使用接口或抽象类的目的是制定好规范,不涉及任何具体的操作,把展现细节的任务交给实现类去完成。 +- 让程序中的所有依赖关系都终止于抽象类或接口。 + +**使用原则** + +- 高层模块不应该依赖低层模块,两个都应该依赖抽象。 +- 抽象不应该依赖细节,细节应该依赖抽象。 + +**使用示例** + +以计算机为例。 + +刚开始的计算机是自成体系的,虽然都是采用同样的设计架构和结构,但组件之间的连接方式不同。如果用 A 公司的电脑,硬盘坏了后只能用 A 公司提供的硬盘。这是一种紧耦合的表现,每个组件将其内部实现暴露给外部对接。 + +后来几家大公司统一了标准,约定好组件之间连接的标准,标准后面具体怎么做,由相应公司自己负责。这样的结果是,我们既可以使用 A 公司的硬盘,也可以使用 B 公司的硬盘。不光如此,不同大小(如 500G 和 200G)、不同结构(如固态硬盘和机械硬盘)的硬盘也可以互换。真正实现了可拔插、易拔插。 + +除了硬盘,其他如 CPU、内存、外设设备等各种设备组件也都实现了标准化接口。所有的对接都发生在接口层面,不需要关心具体的实现细节。 diff --git a/docs/content/design_principles/liskov_substituion_principle.md b/docs/content/design_principles/liskov_substituion_principle.md new file mode 100644 index 0000000..d98e24e --- /dev/null +++ b/docs/content/design_principles/liskov_substituion_principle.md @@ -0,0 +1,29 @@ +# 里氏替换原则 + +里氏替换原则,Liskov Substituion Principle,简称 LSP,一个软件实体如果使用的是一个父类的话,一定适用于其子类,而且它察觉不出父类和子类的区别。也就是说,在软件里面,把父类都替换成它的子类,程序的行为没有变化。简单来说,子类型必须能够替换掉它们的父类型。 + +**使用动机** + +父类能够真正复用(继承),子类也能够在父类的基础上增加新的行为。 + +**如何使用** + +- 父类一般使用抽象类或接口。 +- 抽象类定义公共对象和状态;接口定义公共行为。 +- 子类通过继承父类和接口进行扩展。 + +**使用原则** + +- 子类方法的参数类型必须与父类相匹配或更抽象。 +- 子类的返回值类型必须与父类或其子类相匹配。 +- 子类方法的异常必须与父类能抛出的异常(或其子类)相匹配。 +- 子类不应该加强参数条件限制。 +- 子类不能修改父类的私有成员变量。 + +**使用示例** + +以企鹅和鸟为例。 + +假设鸟是父类,有下蛋和飞翔两个方法。企鹅作为鸟如果继承了父类,就会出现问题,因为企鹅虽然有翅膀但不会飞。所以,这样设计父类和子类是不合理的,它违反了上面提到的原则,企鹅作为子类无法替换父类。 + +合理的做法是将飞翔的行为抽象为接口,父类鸟描述状态和公共方法(比如吃),然后会飞的子类再去实现飞翔接口,不会飞的就不用管了。