设计模式六大原则

设计模式除了常见的23种模式之外,还有六大原则。对这六个原则的遵守并非是和否的问题,而是多和少的问题。制定这六个原则的目的并不是要我们刻板的遵守,而需要根据实际情况灵活运用。

设计模式经常要涉及到UML类图,这里附上图说设计模式中的一章看懂UML类图和时序图,以方便快速复习UML类图中各种符号的含义。

1. 单一职责原则(SRP)

定义: 就一个类而言,应该仅有一个引起它变化的原因。

如果一个类承担的职责过多,就等于把这些职责耦合在一起,一个职责的变化可能会削弱或抑制这个类完成其他职责的能力。这种耦合会导致脆弱的设计,当变化发生时,设计会遭受到意向不到的破坏。如果能够想到多于一个的动机去改变一个类,那么这个类就具有多于一个的职责。

2. 里氏替换原则

定义:子类必须能够替换掉它们的父类

软件里把父类替换成它的子类,程序的行为没有变化。只有当子类可以替换掉父类,软件单位的功能不受到影响时,父类才能真正被复用,而子类也能够在父类的基础上增加新的行为。

例子:一个鸟类,一个企鹅类。鸟有“飞”的行为,企鹅不会飞,所以企鹅不能以父类——鸟的身份出现,即企鹅类不能继承鸟类。

3. 依赖倒置原则

定义:高层模块不应该依赖底层模块,两者都应该依赖抽象;抽象不应该依赖细节,细节应该依赖抽象。

要针对接口编程,不要对实现编程。在Java或C#语言中的表现就是:实现类之间不发生直接的依赖关系,依赖关系是通过接口产生的。依赖倒置是面向对象设计的标志,如果程序中所有的依赖关系都终止于抽象类或接口,就是面向对象的设计。

例子:

  1. CPU、内存等都是针对接口设计的,如果针对实现来设计,内存就要对应到具体的某个品牌的主板,就会出现换内存也要把主板换了的尴尬。
  2. 做项目大多要访问数据库,把访问数据库的代码写成函数,每次做新项目时去调用这些函数,这就叫高层模块依赖低层模块。做新项目时,发现业务逻辑的高层模块都是一样的额,但客户却希望使用不同的数据库,高层模块与低层的访问数据库绑定在一起,没办法复用高层模块。应该两者都依赖约定的接口。

4. 接口隔离原则

定义:客户端不应该依赖它不需要的接口(接口尽量细化),类见的依赖关系应该建立在最小的接口上。

接口“小”是要有限度的,首先不能违反单一职责原则,其次是要高内聚。一个接口只服务于一个子模块或业务逻辑,通过业务逻辑压缩接口中的public方法。

5. 迪米特法则

定义:如果两个类不必彼此直接通信,那么这两个类就不应该发生直接的相互作用。一个对象应该对其他对象有最少的了解。如果一个类需要调用另一个类的某一个方法,可以通过第三者转发这个调用。

该法则的根本思想,是强调了类之间的松耦合。一个类公开的public属性或方法越多,修改时涉及的面和风险也就越大。在设计时需要反复衡量:是否还可以再减少public方法和属性。实践中,如果一个类跳转两次以上才能访问到另一个类,就说明系统过于复杂,需要想办法进行重构了。

6. 开闭原则

定义:软件实体(类、模块、函数等等)应该可以扩展开放,对修改封闭。

面对需求变化,对程序的改动是通过增加新代码进行的,而不是更改现有的代码。但在最初编写代码时,难以预测到变化的产生,这就要求变化发生时,就创建抽象来隔离以后发生的同类变化。开发人员应该仅对程序中呈现出频繁变化的那些部分作出抽象,拒绝不成熟的抽象和抽象本身一样重要。

例子:书店管理图书,IBook接口有getNamegetPricegetAuthor方法,实现类NovelBook实现IBook接口,客户端类BookStore关联IBook接口。

  1. 获取原价格的业务变化成获取打折处理后的价格时,应该扩展一个子类(继承NovelBookOffNovelBook,覆写getPrice方法来获取打折价格。
  2. 若要新增一种计算机类图书,且可以获取其领域,可以新增IComputerBook接口继承IBook,其中包含getScope方法,再增加一个ComputerBook实现类。

最后总结一下:

  • 单一职责原则告诉我们实现类要职责单一
  • 里氏替换原则告诉我们不要破坏继承体系
  • 依赖倒置原则告诉我们要面向接口编程
  • 接口隔离原则告诉我们在设计接口的时候要精简单一
  • 迪米特法则告诉我们要降低耦合
  • 开闭原则是总纲,它告诉我们要对扩展开放,对修改关闭

参考文献:《设计模式之禅(第2版)》第1-6章、《大话设计模式》

当前网速较慢或者你使用的浏览器不支持博客特定功能,请尝试刷新或换用Chrome、Firefox等现代浏览器