http://c.biancheng.net/view/8508.html
https://zhuanlan.zhihu.com/p/85026259
带案例说明:https://www.cnblogs.com/zhaoqingqing/p/4288454.html
简单回顾七大设计原则

单一职责原则

这个原则强调的是“当设计封装一个类时,该类应该只负责一件事”。
说的再直白一点就是:设计目的单一的类。如果一个类的职责越多,它和其他类关联的可能性就越大,耦合程度就越高。
说起来好像很简单,实际上对功能的划分通常也是开发者最头疼的一件事。
解决方案就是对类进行不断的重构,将部分功能抽成新的类,再利用组合的方式将新的类加入到原来的类中,慢慢的就会变成一个类只负责单一功能的实现。

里氏替换原则

这里强调的是“子类必须能够替换父类”
首先里氏替换原则是继承复用的基础,反映了父类与子类之间的关系。
通俗的讲有父类的地方,全部替换成子类,不影响程序的运行,这样就满足里氏替换原则。
那什么样的子类在替换父类时,不会影响程序运行呢?
这种子类可以扩展父类的功能,但不能修改父类的原有功能。这也是对单一职责原则的补充——对扩展开放,对修改关闭。
如果违背了里氏替换原则,会让程序出错的概率大大提升
举个栗子
我们定义了一个父类——鸟,并且带有一个方法可以返回鸟的飞行高度。再定义两个子类:麻雀、企鹅,并且企鹅重写了返回飞行高度的方法,使得返回值为0。当外部需要获取所有鸟类的飞行高度,并作为除数的分母使用,我们都知道0不可以作为分母,这时程序便出错了。
这个栗子便出现了“子类修改父类原有功能”的禁忌,违反了里氏替换原则,也就是不能采用继承结构,要重新设计他们之间的关系。如果非要重写父类的方法,比较通用的做法是:原来的父类和子类都继承一个更通俗的基类,原有的继承关系去掉,采用依赖、聚合,组合等关系代替。
类B继承类A时,除添加新的方法完成新增功外,尽量不要重写父类A的方法,也尽量不要重载父类A的方法。
子类可以扩展父类的功能,但不能改变父类原有的功能。它包含以下4层含义:
1.子类可以实现父类的抽象方法,但不能覆盖父类的非抽象方法。
2.子类中可以增加自己特有的方法。
3.当子类的方法重载父类的方法时,方法的前置条件(即方法的形参)要比父类方法的输入参数更宽松。
4.当子类的方法实现父类的抽象方法时,方法的后置条件(即方法的返回值)要比父类更严格。

依赖倒置原则

这个原则包含了两个主题

  • 高层模块不能依赖于底层模块,两者都应该依赖于抽象概念
  • 抽象接口不应该依赖于实现,而实现应该依赖于抽象接口

这里的抽象概念, 指的是接口或者抽象类,细节就是具体的实现类,所以这是在告诉我们,要面向接口编程,不要面向实现方式编程。
配合上方带案例的博客
所以从这里我们能看出,依赖导致原则也是实现开闭原则的重要途径之一,他的目的是通过面向接口编程,来降低类与类之间的耦合。
在实际编程中,我们一般需要做到如下3点
1.低层模块尽量都要有抽象类或接口,或者两者都有。
2.变量的声明类型尽量是抽象类或接口。使用继承时遵循里氏替换原则。
3.依赖倒置原则的核心就是要我们面向接口编程,理解了面向接口编程,也就理解了依赖倒置。

接口隔离原则

这里强调的是“客户端不应该被迫使用他们用不到的接口方法”, 如果接口过于臃肿,只要接口中出现的方法,不管对依赖于它的类有没有用处,实现类中都必须去实现这些方法,这显然不是好的设计。 如果将这个设计修改为符合接口隔离原则,就必须对接口I进行拆分。
其实就是要求我们对各个类,建立他们专用的接口,而不要试图去建立一个庞大的接口提供给所有需要他的类去调用它。
注意几点
采用接口隔离原则对接口进行约束时,要注意以下几点:
1.接口尽量小,但是要有限度。对接口进行细化可以提高程序设计灵活性是不挣的事实,但是如果过小,则会造成接口数量过多,使设计复杂化。所以一定要适度。
2.为依赖接口的类定制服务,只暴露给调用的类它需要的方法,它不需要的方法则隐藏起来。只有专注地为一个模块提供定制服务,才能建立最小的依赖关系。
3.提高内聚,减少对外交互。使接口用最少的方法去完成最多的事情。
运用接口隔离原则,一定要适度,接口设计的过大或过小都不好。设计接口的时候,只有多花些时间去思考和筹划,才能准确地实践这一原则。

最少知识原则(迪米特法则)

一个对象应该对其他对象保持最少的了解
类与类之间的关系越密切,耦合度越大,当一个类发生改变时,对另一个类的影响也越大。 因此,尽量降低类与类之间的耦合。
对于被依赖的类来说,无论逻辑多么复杂,都尽量地的将逻辑封装在类的内部,对外除了提供的public方法,不对外泄漏任何信息。
迪米特法则还有一个更简单的定义:只与直接的朋友通信。
首先来解释一下什么是直接的朋友:
每个对象都会与其他对象有耦合关系,只要两个对象之间有耦合关系,我们就说这两个对象之间是朋友关系。
耦合的方式很多,依赖、关联、组合、聚合等。其中,我们称出现成员变量、方法参数、方法返回值中的类为直接的朋友, 而出现在局部变量中的类则不是直接的朋友。也就是说,陌生的类最好不要作为局部变量的形式出现在类的内部。
迪米特法则的初衷是降低类之间的耦合,由于每个类都减少了不必要的依赖,因此的确可以降低耦合关系。 但是凡事都有度,虽然可以避免与非直接的类通信,但是要通信,必然会通过一个“中介”来发生联系,过分的使用迪米特原则,会产生大量这样的中介和传递类,导致系统复杂度变大。 所以在采用迪米特法则时要反复权衡,既做到结构清晰,又要高内聚低耦合。

开闭原则

这个原则强调的是“一个类应该对扩展开放,对修改关闭”
其实,我们遵循设计模式前面5大原则,以及使用23种设计模式的目的就是遵循开闭原则。
为了满足这个原则的要求,我们需要将“方法”上升到接口,将“实现”下放到子类中,这样当新增一个需求时,我们重新实现一个子类继承自接口或者旧的子类,然后在新的子类中新增功能,这样就保证了旧的功能没有发生变化(对修改关闭),同时新增了功能(对扩展开放)。

合成复用原则

其实合成复用原则讲的就是如果可以用组合解决问题,就不用继承。
也就是组合优于继承。
为什么组合会优于继承呢?
首先,如果使用了继承,子类重写了父类方法,就会违背里氏替换原则,会让程序增加出错的可能。这里合成复用原则和里氏替换原则又是相辅相成的。
其次,使用继承,子类会依赖于父类的实现,这不利于类的扩展和实现。
最后,C#是无法使用多重继承的,使用组合的方式会比层层继承来的明白,利于项目的维护。
实现这个原则的方式也很简单,是通过将已有的对象纳入新对象中,作为新对象的成员对象来实现的,新对象可以调用已有对象的功能,从而达到复用。