设计模式 六大原则

来源:互联网 发布:淘宝家装设计师平台 编辑:程序博客网 时间:2024/06/10 13:20

之前面试的时候有被问到过这个问题

(一) 单一职责原则

不要存在多余一个导致类变更的原因。(一个类只负责一项职责)

问题:

类T负责两个不同的职责P1、P2,当由于职责P1需求发生改变而需要改变T时,可能会导致原来运行正常的P2功能出现故障。

解决方法:

遵循单一职责原则,分别建立类T1、T2,分别负责P1,P2职责,这样修改类T1时不会影响P2。

遵循单一职责原则的优点有:

  • 降低类的复杂度
  • 提高类的可读性,提高系统的可维护性
  • 变更引起的风险降低,变更是必然的,如果单一职责原则遵守的好,当修改一个功能时,可以显著降低对其他功能的影响。

PS:只要是模块化的程序设计,都实用单一职责原则。

(二)里式替换原则

定义一:如果对每一个类型为T1的对象O1,都有类型为T2的对象O2,使得以T1定义的所有程序P在所有的对象O1都被替换成O2时,程序P的行为没有发生变化,那么类型T2是类型T1的子类型。

定义二:所有引用积累的地方必须能透明的使用其子类的对象

问题:有一个功能P1由类A完成,现在需要对功能P1进行扩展,扩展后的功能是P,其中P由原功能P1和新功能P2组成,新功能P由类A的子类B来完成,则子类B在完后才能新功能P2的同时,有可能会导致原有功能P1发生故障。

解决方法:

使用继承,类B继承类A(最好不要复写A中的方法)

里式替换原则主要来说就是子类可以扩展父类的功能,但是不可改变父类的原有功能

  • 子类可以实现父类的抽象方法,可以不能覆盖非抽象方法
  • 子类可以增加自己特有的方法
  • 子类重载父类方法的时候,方法的前置条件(即方法的形参)要比父类方法的输入参数更宽松。
  • 当子类的方法实现父类的抽象方法时,方法的后置条件(即方法的返回值)要比父类更严格。

(三)依赖倒置原则

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

问题:

类A直接依赖类B,加入要把类A改为依赖类C,则必须通过修改类A的代码来达成。这种情景下的类A一般是高层模块,负责复杂的业务逻辑;类B和类C的底层模块,负责基本的原子操作。加入修改类A,会给程序带来不必要的风险。

解决方法:

把类A修改为依赖接口I,类B和类C各自实现接口I,类A通过接口I间接和类B或者C发生联系,就会降低修改了类A的几率

依赖倒置的本质是:相对于细节的多变性,抽象的东西要稳定的多,以抽象为基础搭建起来的架构比以细节为基础搭建起来的架构要稳定的多。使用接口或者抽象类的目的是制定好规范和契约,而不去涉及任何具体的操作,把展现细节的任务交给他们的实现类去完成。

依赖倒置原则的核心思想是面向接口编程。

在实际的编程中要做到三点:

  • 底层模块尽量要有抽象类或者接口,或者两个都有
  • 变量的声明类型尽量是接口类或者接口
  • 使用继承时遵循里式替换原则

(四)接口隔离原则

客户端不应该依赖不需要的接口:一个类对另一个类的依赖应该建立在最小的接口上。

问题:

类A通过接口I依赖类B,类C通过接口I依赖类D,如果接口I对于类A和类B来说不是最小接口,则类B和类D就必须要实现不需要的方法了。

解决方法:

把臃肿的接口拆分成几个独立的接口,类A和类C分别和他们需要的接口建立依赖关系,也就是接口隔离原则。

接口隔离原则的含义是:建立单一接口,不要建立庞大臃肿的接口,尽量细化接口,接口中的方法尽量少。也就是说,我们要为各个类建立专用的接口,而不要试图去建立一个很庞大的接口供所有依赖它的类去调用。本文例子中,将一个庞大的接口变更为3个专用的接口所采用的就是接口隔离原则。在程序设计中,依赖几个专用的接口要比依赖一个综合的接口更灵活。接口是设计时对外部设定的“契约”,通过分散定义多个接口,可以预防外来变更的扩散,提高系统的灵活性和可维护性。

采用接口隔离原则对接口进行约束时,要注意以下几点:

  • 接口尽量小,但是要有限度。对接口进行细化可以提高程序设计灵活性是不挣的事实,但是如果过小,则会造成接口数量过多,使设计复杂化。所以一定要适度。
  • 为依赖接口的类定制服务,只暴露给调用的类它需要的方法,它不需要的方法则隐藏起来。只有专注地为一个模块提供定制服务,才能建立最小的依赖关系。
  • 提高内聚,减少对外交互。使接口用最少的方法去完成最多的事情。

(三) 迪米特法则

定义:一个对象应该对其他对象保持最少的了解。

问题由来:类与类之间的关系越密切,耦合度越大,当一个类发生改变时,对另一个类的影响也越大。

解决方案:尽量降低类与类之间的耦合。

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

迪米特法则的初衷是降低类之间的耦合,由于每个类都减少了不必要的依赖,因此的确可以降低耦合关系。但是凡事都有度,虽然可以避免与非直接的类通信,但是要通信,必然会通过一个“中介”来发生联系,例如本例中,总公司就是通过分公司这个“中介”来与分公司的员工发生联系的。过分的使用迪米特原则,会产生大量这样的中介和传递类,导致系统复杂度变大。所以在采用迪米特法则时要反复权衡,既做到结构清晰,又要高内聚低耦合。

(六) 开闭原则

这里写图片描述

图中的每一条维度各代表一项原则,我们依据对这项原则的遵守程度在维度上画一个点,则如果对这项原则遵守的合理的话,这个点应该落在红色的同心圆内部;如果遵守的差,点将会在小圆内部;如果过度遵守,点将会落在大圆外部。一个良好的设计体现在图中,应该是六个顶点都在同心圆中的六边形。

这里写图片描述

在上图中,设计1、设计2属于良好的设计,他们对六项原则的遵守程度都在合理的范围内;设计3、设计4设计虽然有些不足,但也基本可以接受;设计5则严重不足,对各项原则都没有很好的遵守;而设计6则遵守过渡了,设计5和设计6都是迫切需要重构的设计。

原创粉丝点击