设计模式七大原则

设计模式带来的好处

  • 提高代码可重用性
  • 提高代码可读性
  • 提高代码可扩展性
  • 提高代码可靠性
  • 使程序呈现高内聚,低耦合的特性
设计模式七大原则,其实就是在编程过程中应当遵守的原则,也是各种设计模式的基础,七大原则如下:
  • 单一职责原则
  • 接口隔离原则
  • 依赖倒置原则
  • 里氏替换原则
  • 开闭原则
  • 迪米特法则
  • 合成复用原则
下面对这一原则一一介绍。
1 单一职责原则
对类来说,一个类只负责一项职责。如果一个类A负责两个不同的职责,当其中一个职责需求需要变更时,可能会使另一个职责也发生改变。
单一职责原则比较好理解,就不做过多介绍。使用单一职责原则,可以降低类的复杂度,使一个类只负责一项职责,降低需求变更引起的风险。
2 接口隔离原则
客户端不应该依赖它不需要的接口,即一个类对另一个类的依赖应该建立再最小的接口上。
【设计模式七大原则】什么是一个类的依赖对另一个类的依赖应该建立再最小接口上呢?首先要理解的是,当一个类要依赖另一个类时,一般是通过接口来实现的。如下图:
设计模式七大原则
文章图片

ClassA要依赖ClassB,如ClassA中有一个成员变量为ClassB,那么这个变量的类型到底是ClassB还是Interface呢?应是Interface,即变量名b1。why?为了方便修改和扩展。如果以后ClassB过时了,需要有一个新的类ClassC继承Interface,那么,完全不影响ClassA的内部,只需要将ClassC的实例传给ClassA即可。
接下来就要理解什么是最小接口了,看下面这个图:
设计模式七大原则
文章图片

ClassA通过Interface依赖ClassC,ClassB通过Interface依赖ClassD。
但是,ClassA中只用到了method1,2,3。而ClassB只用到了method1,4,5。这时候就违反了接口隔离原则。应为ClassA依赖了它不需要的接口method4,5。ClassB同理。且ClassC和ClassD要实现不需要的接口。应该改为下图:
设计模式七大原则
文章图片

当然,也可以让Interface2和Interface3都继承Interface1。
3 依赖倒置原则
高层模块不应该依赖低层模块,二者都应该依赖其抽象
抽象不应该依赖细节,细节应该依赖抽象
中心思想是面向接口编程
依赖倒置原则设计理念在于,相对于细节的多变性,抽象的东西要稳定的多。使用抽象的目的是制定好规范,而不涉及任何具体的操作,把展现细节的任务交给他们的实现类完成。下面来举例:
有一个Person对象,需要接受电子邮件的消息:
设计模式七大原则
文章图片

Person类的receive方法中调用Email的getInfo方法获取。但是,如果还有接收微信、QQ的消息呢,以后还要扩展其他的方式呢?这时就不得不修改Person类的代码。如果采用下图实现,就不会遇到这种问题:
设计模式七大原则
文章图片

这是,如果以后要扩展其他方式,只需要增加一个类继承IReceiver即可,不需要修改Person类。
4 里氏替换原则
如果对于类型为T1的对象o1,都有类型为T2的对象o2,使得T1定义的所有程序P在所有的对象o1都换成o2时,程序P的行为没有发生变化,那么类型T2是T1的子类型。
换句话说,就是所有引用基类的地方必须能透明的使用子类对象,更通俗的说,所有使用基类的地方都必须能用子类代替。
要准许里氏替换原则,就是在子类中尽量不要重写父类的方法。
继承在给程序带来便利的同时,也带来了弊端。继承包含这样一层含义,父类中凡是已经实现好的方法,实际上是在设定规范和契约,虽然它不强制要求所有的子类必须遵循这些契约,但如果子类对这些已经实现的方法随意修改,就会对继承体系造成破坏。里氏替换原则告诉我们,在适当的情况下,可以通过聚合、组合、依赖来解决问题。
如果说无法避免,可以考虑再往上抽象出一个更加基础的类。
5 开闭原则
一个软件实体如类,模块和函数,应该对扩展开放,对修改关闭。
当软件需要变化时,尽量通过扩展软件实体的行为来实现变化,而不是通过修改以后的代码来实现变化。
如在依赖倒置原则中举的例子,当需要增加一种接受信息的方式时,可以扩展一个类继承IReceiver类,而不用修改原有的代码,也不会影响客户端的代码。
6 迪米特法则
一个对象应该对其他对象保持最少的了解,即最少知道原则。
所谓最少知道原则,即一个类对自己依赖的类知道的越少越好。也就是说,不管别依赖的类多么复杂,都尽量将逻辑封装在类的内部。迪米特法则的核心是降低类之间的耦合。
7 聚合/组合复用原则
尽量使用聚合/组合的方法,而不是继承
在里氏替换原则中提到过,在适当的时候,可以通过组合或聚合的方式来解决问题。所谓组合/聚合,就是一个类中保存了另一个类的引用,如ClassA中有一个类型为ClassB的成员变量,ClassA就采用了组合/聚合的方式。组合与聚合的区别在于,组合代表两者间的关系更为紧密,比如汽车与车轮的关系,没有车轮,不可缺少。而聚合代表两者间的关系较弱,比如树木与森林的关系,缺少一棵树,但不会影响森林的存在。
总结
  • 找出应用可能需要变化之处,把它们独立出来,不要和那些不需要变化的代码混在一起
  • 针对接口编程,而不是准对实现编程
  • 为了交互对象之间的松耦合而努力

    推荐阅读