首页 > 编程语言 >C#设计模式读书笔记之设计模式的设计原则

C#设计模式读书笔记之设计模式的设计原则

时间:2022-11-29 20:36:20浏览次数:42  
标签:设计模式 原则 读书笔记 C# 子类 对象 使用 手枪 父类


设计模式的设计原则:

(重要性从上往下排列)

开闭原则:对扩展开放,对修改关闭

依赖倒转原则:高层模块不应该依赖底层模块,它们都应该依赖抽象;要针对抽象层编程,而不要针对具体类编程。

单一职责原则:类的职责要单一,不能将太多的职责放在一个类中

里氏代换原则:使用基类对象的地方都可以使用子类对象,因此在程序中尽量使用基类类型来对对象进行定义,而在运行时再确定其子类类型,用子类对象来替换父类对象。

合成复用原则:指在一个新的对象里通过组合、聚合关系来使用一些已有的对象,使之成为新对象的一部分;新对象通过调用已有对象的方法达到复用其已有功能的目的。简言之:要尽量使用组合/聚合关系,少用继承。

迪米特原则:指一个软件实体应当尽可能少的与其他实体发生相互作用。这样,当一个模块修改时,就会尽量少的影响其他的模块,扩展会相对容易,这是对软件实体之间通信的限制,它要求限制软件实体之间通信的宽度和深度。

接口隔离原则:指使用多个专门的接口,而不使用单一的总接口。 一旦一个接口太大,则需要将它分割成一些更细小的接口,使用该接口的客户端仅需知道与之相关的方法即可。

设计模式总概况:

C#设计模式读书笔记之设计模式的设计原则_设计模式

开闭原则:

对扩展开放,对修改关闭

C#设计模式读书笔记之设计模式的设计原则_父类_02

图(1)

C#设计模式读书笔记之设计模式的设计原则_子类_03

图(2)

 

分析总结:

图(1):客户端的一个方法直接调用加法类,但是我想添加一个减法类,你就会发现添加减法类就得改变加法类中代码(用switch语句实现),这就违背了“开闭原则”,于是我们就应该重新重构。

如图(2)在这个图中我们添加了一个运算类的父类,这样我们再添加减法类的时候就不用修改原来的代码。

 

依赖倒转原则:

高层模块不应该依赖底层模块,它们都应该依赖抽象;要针对抽象层编程,而不要针对具体类编程。

C#设计模式读书笔记之设计模式的设计原则_父类_04

图(一)

C#设计模式读书笔记之设计模式的设计原则_复用_05

图(二)

 

分析总结:

图(一)为什么要到图(二)哪?因为该系统可能需要增加新的数据源或者新的文件格式,每增加一个新的类型的数据源或者新的类型的文件格式,客户类MainClass都需要修改源代码,以便使用新的类,但违背了开闭原则。现使用依赖倒转原则对其进行重构。

 

里氏代换原则:

使用基类对象的地方都可以使用子类对象,因此在程序中尽量使用基类类型来对对象进行定义,而在运行时再确定其子类类型,用子类对象来替换父类对象。

 

子类可以扩展父类的功能,但不能改变父类原有的功能。

父类能出现的地方都可以用子类来代替,而且换成子类也不会出现任何错误或异常,而使用者也无需知道是父类还是子类,但反过来则不成立。总之,就是抽象。

 

如果两个具体的类A,B之间的关系违反了里氏代换原则的设计,根据具体的情况进行重构。创建一个新的抽象类C,作为两个具体类的超类,将A,B的共同行为移动到C中来解决问题。

举例:士兵使用手枪进行射击,实现结果为:手枪小,便于携带;手枪一次只能发射一颗子弹;手枪开始射击。
1. 新建一个手枪类HandGun,介绍手枪的特点,代码如下:

C#设计模式读书笔记之设计模式的设计原则_子类_06

2. 新建一个士兵类Soldier,包含手枪的相关方法,代码如下:

C#设计模式读书笔记之设计模式的设计原则_子类_07

3. 在类LSPFragment中实现士兵用手枪进行射击,代码如下:

C#设计模式读书笔记之设计模式的设计原则_父类_08

4. 运行后的结果为:

C#设计模式读书笔记之设计模式的设计原则_复用_09

现在我们需要实现士兵使用步枪进行射击,于是我们就要新增步枪类RifleGun,并且要去修改士兵类Soldier。

情况二:士兵使用步枪进行射击,实现结果为:步枪长,不益于携带;步枪可以连续射击;步枪开始射击。
1.新建一个步枪类RifleGun,介绍步枪的特点,代码如下:

C#设计模式读书笔记之设计模式的设计原则_设计模式_10

2. 修改士兵类Soldier,包含手枪和步枪的相关方法,代码如下:

C#设计模式读书笔记之设计模式的设计原则_设计原则_11

3. 修改类LSPFragment,分别实现士兵用手枪和步枪进行射击,代码如下:

C#设计模式读书笔记之设计模式的设计原则_设计模式_12

4. 运行后的结果为:

C#设计模式读书笔记之设计模式的设计原则_父类_13

以上的实现方式可以看出,一旦新增功能(武器),就会去修改类Soldier和类LSPFragment,这样不仅会影响到原有的功能,
扩展起来也十分不方便,假设逻辑比较复杂的话,就需要去修改或重构大量的代码。

于是就要使用里氏替换原则来解决这个问题,新增一个类BaseGun,包含武器的特点和射击动作的方法,让手枪类HandGun和
步枪类RifleGun都继承于它,分别来实现,代码如下:

1. 新增类BaseGun,包含武器的特点和射击动作的方法,代码如下:

C#设计模式读书笔记之设计模式的设计原则_设计原则_14

2. 让手枪类HandGun和步枪类RifleGun都继承于它,分别来实现以上两个方法,代码如下:

C#设计模式读书笔记之设计模式的设计原则_复用_15

C#设计模式读书笔记之设计模式的设计原则_设计模式_16

3. 修改士兵类Soldier,让它依赖类BaseGun,代码如下:

C#设计模式读书笔记之设计模式的设计原则_设计原则_17

4. 修改类LSPFragment,实现士兵用手枪和步枪进行射击,代码如下:

C#设计模式读书笔记之设计模式的设计原则_复用_18

5. 运行后的结果同上。
以上实现方式可以看出,子类(手枪类HandGun和步枪类RifleGun)继承父类BaseGun,并完全实现父类BaseGun中的抽象方法来实现功能。
其中,士兵类Soldier依赖于抽象类BaseGun来调用相应的方法,在类LSPFragment中可以看出,父类都可以用子类来代替,但不能改变父类原有的功能,在子类中可以任意扩展功能,这就是所谓的“所有引用基类的地方必须能透明地使用其子类的对象。”

 

接口隔离原则:

接口隔离原则是指使用多个专门的接口,而不使用单一的总接口。 一旦一个接口太大,则需要将它分割成一些更细小的接口,使用该接口的客户端仅需知道与之相关的方法即可。

C#设计模式读书笔记之设计模式的设计原则_设计模式_19

图(一)

C#设计模式读书笔记之设计模式的设计原则_子类_20

图(二)

 

分析总结:

图(一)为什么到图(二)哪?因为这样做既满足了接口隔离原则,又满足了单一原则,何乐而不为呢,但是也带来了很多的不便,类增多了。

 

合成复用原则:

指在一个新的对象里通过组合、聚合关系来使用一些已有的对象,使之成为新对象的一部分;调用已有对象的方法达到复用其已有功能的目的。简言之:要尽量使用组合/聚合关系,少用继承。

 

组合/聚合可以使系统更加灵活,类与类之间的耦合度降低,一个类的变化对其他类造成的影响相对较少,因此一般首选使用组合/聚合来实现复用;其次才考虑继承,在使用继承时,需要严格遵循里氏代换原则,有效使用继承会有助于对问题的理解,降低复杂度,而滥用继承反而会增加系统构建和维护的难度以及系统的复杂度,因此需要慎重使用继承复用。

 

迪米特原则:

指一个软件实体应当尽可能少的与其他实体发生相互作用。这样,当一个模块修改时,就会尽量少的影响其他的模块,扩展会相对容易,这是对软件实体之间通信的限制,它要求限制软件实体之间通信的宽度和深度。

C#设计模式读书笔记之设计模式的设计原则_设计模式_21

图(一)

 

C#设计模式读书笔记之设计模式的设计原则_父类_22

图(二)

 

分析总结:

图(一)为什么到图(二)哪?因为这样就可以降低类的耦合性,是类中功能更加单一,相当于外观模式。

 

标签:设计模式,原则,读书笔记,C#,子类,对象,使用,手枪,父类
From: https://blog.51cto.com/u_6871414/5896977

相关文章

  • Unity-Animator Override Controller
    AnimatorOverrideController是一种资产类型,允许您扩展现有的AnimatorController,替换使用的特定动画,但保留原始结构,参数和逻辑。允许您创建相同基本状态机的多个变体,但每......
  • ClassLoader
    ClassLoader:用来加载Class的。负责将Class的字节码形式转换成内存形式的Class对象。字节码可以来自于磁盘文件*.class,也可以是jar包里的*.class,也可以来自远程......
  • C++函数编译原理和成员函数的实现
    对象的内存中只保留了成员变量,除此之外没有任何其他信息,程序运行时不知道stu的类型为Student,也不知道它还有四个成员函数setname()、setage()、setscore()、show(),C++......
  • sizeof(struct)和sizeof(union)的结果分析及其原因
    一个错误有的时候,在脑海中停顿了很久的“显而易见”的东西,其实根本上就是错误的。就拿下面的问题来看:structT{charch;inti;};使用sizeof(T),将得到什么样的答案呢......
  • leetcode 1976.到达目的地的方案数
    问题描述:你在一个城市里,城市由n 个路口组成,路口编号为 0 到 n-1 ,某些路口之间有双向 道路。输入保证你可以从任意路口出发到达其他任意路口,且任意两个路口之间......
  • C++多态性
    虚函数是C++中用于实现多态(polymorphism)的机制。核心理念就是通过基类访问派生类定义的函数。虚函数    是在基类中使用关键字virtual声明的函数。在派生类中重......
  • C#数据结构-Dictionary实现
    在看过一篇大神写的​​《带你看懂Dictionary的内部实现》​​,对Dictionary的内部实现有了一个清晰的了解,但纸上得来终觉浅,作为程序员,还是自己调试一下代码,记忆更深刻,为此专......
  • C#数据结构-红黑树实现
    二叉查找树,他对于大多数情况下的查找和插入在效率上来说是没有问题的,但是他在最差的情况下效率比较低。红黑树保证在最坏的情况下插入和查找效率都能保证在对数的时间复杂度......
  • C#数据结构-有限状态机
    有限状态机FSM的要点是:  拥有一组状态,并且可以在这组状态之间进行切换。  状态机同时只能在一个状态。  一连串的输入或事件被发送给机器。  每个状态都......
  • 【最通俗易懂】A*寻路算法C#实现
    A*算法其实也不复杂,首先有以下几个概念:开启的节点表(OpenList)存放着所有的待检测的节点(坐标),每次都会从其中寻找出符合某个条件的节点。关闭的节点表(ClosedList)存放着所有......