设计模式的设计原则:
(重要性从上往下排列)
开闭原则:对扩展开放,对修改关闭
依赖倒转原则:高层模块不应该依赖底层模块,它们都应该依赖抽象;要针对抽象层编程,而不要针对具体类编程。
单一职责原则:类的职责要单一,不能将太多的职责放在一个类中
里氏代换原则:使用基类对象的地方都可以使用子类对象,因此在程序中尽量使用基类类型来对对象进行定义,而在运行时再确定其子类类型,用子类对象来替换父类对象。
合成复用原则:指在一个新的对象里通过组合、聚合关系来使用一些已有的对象,使之成为新对象的一部分;新对象通过调用已有对象的方法达到复用其已有功能的目的。简言之:要尽量使用组合/聚合关系,少用继承。
迪米特原则:指一个软件实体应当尽可能少的与其他实体发生相互作用。这样,当一个模块修改时,就会尽量少的影响其他的模块,扩展会相对容易,这是对软件实体之间通信的限制,它要求限制软件实体之间通信的宽度和深度。
接口隔离原则:指使用多个专门的接口,而不使用单一的总接口。 一旦一个接口太大,则需要将它分割成一些更细小的接口,使用该接口的客户端仅需知道与之相关的方法即可。
设计模式总概况:
开闭原则:
对扩展开放,对修改关闭
图(1)
图(2)
分析总结:
图(1):客户端的一个方法直接调用加法类,但是我想添加一个减法类,你就会发现添加减法类就得改变加法类中代码(用switch语句实现),这就违背了“开闭原则”,于是我们就应该重新重构。
如图(2)在这个图中我们添加了一个运算类的父类,这样我们再添加减法类的时候就不用修改原来的代码。
依赖倒转原则:
高层模块不应该依赖底层模块,它们都应该依赖抽象;要针对抽象层编程,而不要针对具体类编程。
图(一)
图(二)
分析总结:
图(一)为什么要到图(二)哪?因为该系统可能需要增加新的数据源或者新的文件格式,每增加一个新的类型的数据源或者新的类型的文件格式,客户类MainClass都需要修改源代码,以便使用新的类,但违背了开闭原则。现使用依赖倒转原则对其进行重构。
里氏代换原则:
使用基类对象的地方都可以使用子类对象,因此在程序中尽量使用基类类型来对对象进行定义,而在运行时再确定其子类类型,用子类对象来替换父类对象。
子类可以扩展父类的功能,但不能改变父类原有的功能。
父类能出现的地方都可以用子类来代替,而且换成子类也不会出现任何错误或异常,而使用者也无需知道是父类还是子类,但反过来则不成立。总之,就是抽象。
如果两个具体的类A,B之间的关系违反了里氏代换原则的设计,根据具体的情况进行重构。创建一个新的抽象类C,作为两个具体类的超类,将A,B的共同行为移动到C中来解决问题。
举例:士兵使用手枪进行射击,实现结果为:手枪小,便于携带;手枪一次只能发射一颗子弹;手枪开始射击。
1. 新建一个手枪类HandGun,介绍手枪的特点,代码如下:
2. 新建一个士兵类Soldier,包含手枪的相关方法,代码如下:
3. 在类LSPFragment中实现士兵用手枪进行射击,代码如下:
4. 运行后的结果为:
现在我们需要实现士兵使用步枪进行射击,于是我们就要新增步枪类RifleGun,并且要去修改士兵类Soldier。
情况二:士兵使用步枪进行射击,实现结果为:步枪长,不益于携带;步枪可以连续射击;步枪开始射击。
1.新建一个步枪类RifleGun,介绍步枪的特点,代码如下:
2. 修改士兵类Soldier,包含手枪和步枪的相关方法,代码如下:
3. 修改类LSPFragment,分别实现士兵用手枪和步枪进行射击,代码如下:
4. 运行后的结果为:
以上的实现方式可以看出,一旦新增功能(武器),就会去修改类Soldier和类LSPFragment,这样不仅会影响到原有的功能,
扩展起来也十分不方便,假设逻辑比较复杂的话,就需要去修改或重构大量的代码。
于是就要使用里氏替换原则来解决这个问题,新增一个类BaseGun,包含武器的特点和射击动作的方法,让手枪类HandGun和
步枪类RifleGun都继承于它,分别来实现,代码如下:
1. 新增类BaseGun,包含武器的特点和射击动作的方法,代码如下:
2. 让手枪类HandGun和步枪类RifleGun都继承于它,分别来实现以上两个方法,代码如下:
3. 修改士兵类Soldier,让它依赖类BaseGun,代码如下:
4. 修改类LSPFragment,实现士兵用手枪和步枪进行射击,代码如下:
5. 运行后的结果同上。
以上实现方式可以看出,子类(手枪类HandGun和步枪类RifleGun)继承父类BaseGun,并完全实现父类BaseGun中的抽象方法来实现功能。
其中,士兵类Soldier依赖于抽象类BaseGun来调用相应的方法,在类LSPFragment中可以看出,父类都可以用子类来代替,但不能改变父类原有的功能,在子类中可以任意扩展功能,这就是所谓的“所有引用基类的地方必须能透明地使用其子类的对象。”
接口隔离原则:
接口隔离原则是指使用多个专门的接口,而不使用单一的总接口。 一旦一个接口太大,则需要将它分割成一些更细小的接口,使用该接口的客户端仅需知道与之相关的方法即可。
图(一)
图(二)
分析总结:
图(一)为什么到图(二)哪?因为这样做既满足了接口隔离原则,又满足了单一原则,何乐而不为呢,但是也带来了很多的不便,类增多了。
合成复用原则:
指在一个新的对象里通过组合、聚合关系来使用一些已有的对象,使之成为新对象的一部分;调用已有对象的方法达到复用其已有功能的目的。简言之:要尽量使用组合/聚合关系,少用继承。
组合/聚合可以使系统更加灵活,类与类之间的耦合度降低,一个类的变化对其他类造成的影响相对较少,因此一般首选使用组合/聚合来实现复用;其次才考虑继承,在使用继承时,需要严格遵循里氏代换原则,有效使用继承会有助于对问题的理解,降低复杂度,而滥用继承反而会增加系统构建和维护的难度以及系统的复杂度,因此需要慎重使用继承复用。
迪米特原则:
指一个软件实体应当尽可能少的与其他实体发生相互作用。这样,当一个模块修改时,就会尽量少的影响其他的模块,扩展会相对容易,这是对软件实体之间通信的限制,它要求限制软件实体之间通信的宽度和深度。
图(一)
图(二)
分析总结:
图(一)为什么到图(二)哪?因为这样就可以降低类的耦合性,是类中功能更加单一,相当于外观模式。
标签:设计模式,原则,读书笔记,C#,子类,对象,使用,手枪,父类 From: https://blog.51cto.com/u_6871414/5896977