设计模式 - 6大原则 SOLID

设计模式 - 6大原则

1. 单一职责原则(SRP)

单一职责原则(SRP,Single Responsibility Principle),强调的是职责分离,在某种程度上对职责的理解是构成了不同类之间的耦合关系的设计关键。

核心思想:一个类最好只做一件事,只有一个引起它变化的原因。

具体体现:

  • 所说的职责一般指功能,然而单一职责原则是由引起变化的原因决定,
  • 一个类只负责一个功能领域中的相应职责。
  • 一个类最好只做一件事,这是一个职责的粒度划分,可大可小,小到一个方法,大到一批,甚至关联到许多其它模块,只要是这个类的职责所在就行,就是所说的高内聚。
  • 一个类最好只做一件事,事情越少越稳定,要设计的类尽量简单。

单一职责原则可以看成是低耦合、高内聚在面向对象原则上的引申,将职责定义为引起变化的原因,以提高内聚性来减少变化的原因。职责过多,变化的原因也就多,将导致职责之间的依赖,互相产生影响,从而极大的损伤其内聚性和耦合度。虽然单一职责原则如此简单,并且被认为是常识,但是即便是经验丰富的程序员写出的程序,也会有违背这一原则的代码存在。为什么会出现这种现象呢?因为有职责扩散。所谓职责扩散,就是因为某种原因,职责P被分化为粒度更细的职责P1和P2。比如:类T只负责一个职责P,这样设计是符合单一职责原则的。后来由于某种原因,也许是需求变更了,也许是程序的设计者境界提高了,需要将职责P细分为粒度更细的职责P1,P2,这时如果要使程序遵循单一职责原则,需要将类T也分解为两个类T1和T2,分别负责P1、P2两个职责。但是在程序已经写好的情况下,这样做简直太费时间了。所以,简单的修改类T,用它来负责两个职责是一个比较不错的选择,虽然这样做有悖于单一职责原则。(这样做的风险在于职责扩散的不确定性,因为我们不会想到这个职责P,在未来可能会扩散为P1,P2,P3,P4……Pn。所以记住,在职责扩散到我们无法控制的程度之前,立刻对代码进行重构。)

应用建议:

  • 一个类只有一个引起它变化的原因,否则应当考虑重构。
  • 如果多个职责总是同时发生改变则可将它们封装在同一类中。
  • SRP由引起变化的原因决定,而不由功能职责决定;或者说由最小引起变化的职责决定。
  • 测试驱动开发有助于实现合理分离功能的设计。

 2. 依赖倒置原则(DIP)

依赖倒置原则(DIP,Dependency Inversion Principle),通过抽象机制有效解决类层次之间的关系,降低耦合的粒度,实现对抽象的依赖是依赖倒置的核心思想。

核心思想:依赖于抽象,面向接口编程

具体体现:

  • 高层模块不应该依赖于低层模块,二者都应该依赖于抽象。
  • 抽象不应该依赖于具体,具体应该依赖于抽象。

高层模块一般是负责复杂的业务逻辑,低层模块负责基本的原子操作;修改高层模块会给程序带来不必要的风险。上面两点也就是解决方案,依赖倒置原则基于这样一个事实:相对于细节的多变性,抽象的东西要稳定的多。以抽象为基础搭建起来的架构比以细节为基础搭建起来的架构要稳定的多。抽象指的是接口或者抽象类,细节就是具体的实现类,使用接口或者抽象类的目的是制定好规范和契约,而不去涉及任何具体的操作,把展现细节的任务交给他们的实现类去完成。

应用建议:

  • 抽象的稳定性决定了系统的稳定性,因为抽象是保持不变的,依赖于抽象是面向对象程序设计的精髓,也是依赖倒置的核心思想。
  • 依赖于抽象是一个通用的规则,而某些依赖于细节在所难免的,必须权衡抽象和具体的取舍,方法不是一成不变的。
  • 依赖于抽象就是要对接口编程,不要对实现编程

3. 接口隔离原则(ISP)

接口隔离原则(ISP,Interface Segregation Principle)

核心思想:使用多个小的专门接口,而不要使用一个大的总接口。

具体体现:

  • 接口应该是内聚的,应该避免出现胖接口。
  • 一个类对另一个类的依赖应该建立在最小的接口上,不要强迫依赖不用的方法,这是一种接口污染。

将功能相近的接口合并,可能造成接口污染,实现内聚的接口才是接口设计的基本原则。接口隔离原则能够保证系统的扩展和修改的影响不会扩展到系统的其他部分,一定程度上保证了开放封闭原则。

应用建议:

  • 委托分离,通过增加一二新的类型来委托客户请求,隔离客户和接口的直接依赖,但会增加系统的开销。
  • 多重继承分离,通过接口多继承来实现客户需求,这种方式值得推荐。
  • 注意控制接口的粒度,接口不能太小,如果太小会导致系统中接口泛滥,不利于维护

4. 里氏替换原则(LSP)

里氏替换原则(LSP,Liskov Substitution Principle)是关于继承机制的原则,是实现开放封闭原则的具体规范,违反了里氏替换原则必然违反了开放封闭原则。

核心思想:子类必须能够替换其基类。

具体体现:

  • 子类继承基类,是一种IS-A关系,只能说子类 IS-A 基类,不能反过来,该原则说的就是处理继承问题的原则。
  • 父类的非抽象方法,不应该被子类重写,重写了就会改变原来父类的方法,造成意想不到的结果,就不能完全代表父类了,如果有意要子类重写请声明虚方法或者抽象方法。

里氏替换原则告诉我们,在软件中将一个基类对象替换成它的子类对象,程序将不会产生任何错误和异常;反过来则不成立,如果一个软件实体使用的是一个子类对象的话,那么它不一定能够使用基类对象来替换。继承作为面向对象三大特性之一,在给程序设计带来巨大便利的同时,也带来了弊端。比如使用继承会给程序带来侵入性,程序的可移植性降低,增加了对象间的耦合性,如果一个类被其他的类所继承,则当这个类需要修改时,必须考虑到所有的子类,并且父类修改后,所有涉及到子类的功能都有可能会产生故障。

应用建议:

  • 里氏替换原则是关于继承机制的原则,违反了里氏替换原则必然违反了开放封闭原则。里氏替换原则能够保证系统有良好的扩展性,同时实现了多态的抽象机制,减少代码冗余,避免运行期的类型判断。
  • 子类必须满足基类和客户端对其行为的约定,客户端对行为的期望在基类和子类必须保持一致。
  • IS-A是基于行为的方式,它依赖于客户端的调用方式,对象的行为方式才是值得关注的要素。
  • 子类的异常必须控制在基类可以预计的范围,否则将导致替换违规。
  • 子类的所有方法必须在父类中声明,或子类必须实现父类中声明的所有方法。如果一个方法只存在子类中,在父类中不提供相应的声明,则无法在以父类定义的对象中使用该方法。
  • 尽量把父类设计为抽象类或者接口,让子类继承父类或实现父接口,并实现在父类中声明的方法,运行时,子类实例替换父类实例,我们可以很方便地扩展系统的功能,同时无须修改原有子类的代码,增加新的功能可以通过增加一个新的子类来实现。

5. 迪米特原则(LKP)

迪米特法则(Law of Demeter)又叫作最少知识原则(LKP,Least Knowledge Principle),就是说一个对象应当对其他对象有尽可能少的了解,类与类之间的了解的越多,关系越密切,耦合度越大,当一个类发生改变时,另一个类也可能发生变化。

核心思想:最少依赖,尽量降低类与类之间的耦合

具体体现:

  • 类内部应该高内聚,设置相应的权限,有选择的暴露方法(这就是封装的奥秘)。
  • 类的依赖关系尽量减少,保持简单和独立,降低耦合。

通俗的来讲,就是一个类对自己依赖的类知道的越少越好。也就是说,对于被依赖的类来说,无论逻辑多么复杂,都尽量地的将逻辑封装在类的内部,对外除了提供的public方法,不对外泄漏任何信息。迪米特法则还有一个更简单的定义:只与直接的朋友通信。首先来解释一下什么是直接的朋友:每个对象都会与其他对象有耦合关系,只要两个对象之间有耦合关系,我们就说这两个对象之间是朋友关系。耦合的方式很多,依赖、关联、组合、聚合等。其中,我们称出现成员变量、方法参数、方法返回值中的类为直接的朋友,而出现在局部变量中的类则不是直接的朋友。也就是说,陌生的类最好不要作为局部变量的形式出现在类的内部。

应用建议:

  • 在类的划分上,应当创建弱耦合的类,类与类之间的耦合越弱,就越有利于实现可复用的目标。
  • 在类的结构设计上,每个类都应该控制或降低成员的访问权限。
  • 在类的设计上,只要有可能,一个类应当设计成不变的类。
  • 在对其他类的应用上,一个对象对其他类的对象的应用应该降到最低。
  • 尽量限制局部变量的有效范围。

6. 开放封闭原则(OCP)

开放封闭原则(OCP,Open Close Principle)是所有面向对象原则的核心。软件设计本身所追求的目标就是封装变化,降低耦合,而开放封闭原则正是对这一目标的最直接的体现。其它原则很多时候都是为了实现这一目标服务的,如 里氏替换原则。

核心思想:软件实体应该是可扩展的,而不是可修改的。也就是说,对扩展开放,而对修改是封闭的。

具体体现:

  • 对扩展开放,意味着有新需求或变化时,可以对现有代码进行扩展,以适应新的情况。
  • 对修改封闭,意味着类一旦设计完成,就可以独立完成其工作,而不要对类进行任何修改。

实现开放封闭原则的核心思想就是对抽象编程,而不是对具体编程,因为抽象是相对稳定的。让类依赖于固定的抽象,所以对修改是封闭的;而通过面向对象的继承和多态机制,可以实现对抽象体的继承,通过覆写其方法来改变固有行为,实现扩展方法,所以对扩展就是开放的,这是实现该原则的基本思路。

应用建议:

  • 开放封闭原则是最为重要的原则,里氏替换等原则为该原则提供保证。
  • 封装变化,是实现开放封闭原则的重要手段,对于经常发生变化的涨停一般将其封装为一个抽象。
  • 拒绝滥用抽象,只将经常变化的部分进行抽象(这种经验可以从设计模式的学习与应用中获得)。    

以上六个原则可以总称为SOLID原则

  •   S:  Single Responsibility Principle 
  •   O: Open Close Principle  
  •   L: Liskov Substitution Principle & Law of Demeter
  •   I: Interface Segregation Principle
  •   D: Dependency Inversion Principle

转载请注明出处:https://www.cnblogs.com/lichu-lc/p/12317675.html

参考:

[设计模式原则]第一回:单一职责原则

[设计模式原则]第二回:依赖倒置原则

[设计模式原则]第三回:接口隔离原则

[设计模式原则]第四回:里氏替换原则

[设计模式原则]第五回:迪米特原则

[设计模式原则]第六回:开放封闭原则

软件设计-设计模式六大原则

posted @ 2020-02-16 20:06  double蠢  阅读(278)  评论(0编辑  收藏  举报