设计原则概述

可维护性

可维护性是指软件能够被理解、改正、适应及扩展的难易度。

可复用性

可复用性是指软件能够被重复使用的难易程度。

单一职责原则

Single Responsibility Principle,SRP

定义:一个对象应该只包含单一的职责,并且该指责被完整的封装在一个类中

用于控制类的粒度大小

单一职责原则是实现高内聚、低耦合的指导方针,它是最简单但又最难运用的原则,需要设计人员发现类的不同职责并将其分离,而发现类的多重职责需要设计人员具有较强的分析设计能力和相关实践经验。

开闭原则

Open-Closed Principle,OCP

软件实体应当对扩展开放,对修改关闭

开闭原则是面向对象的可复用设计的第一块基石  

在开闭原则的定义中,软件实体可以指一个软件模块、一个由多个类组成的局部结构或一个独立的类。开闭原则就是指软件实体应尽量在不修改原有代码的情况下进行扩展。
为了满足开闭原则,需要对系统进行抽象化设计,抽象化是开闭原则的关键。
评价设计原则时,开闭原则会被作为一个重要的评价依据,以判断该模式设计的系统是否具备良好的灵活性和扩展性。

里氏替换原则

Liskov Substitution Principle,LSP

所有引用基类的地方必须能透明的使用其子类的对象

实现开闭原则的重要方式之一

由于在使用基类对象的地方都可以使用子类对象,因此在程序中浸凉使用基类类型对对象进行定义,而在运行时再确定其子类类型,用子类对象来替换父类对象。

最好是将父类设计为抽象或者接口,让子类继承父类或实现父接口,并实现在弗雷中声明的方法,在运行时子类替换父类实例,可以很方便的扩展系统功能,无需修改原有子类的代码,增加新的功能可以通过增加一个新的子类来实现。

里氏替换原则是开闭原则目标的基础

依赖倒转原则

Dependence Inversion Principle,DIP

高层模块不应该依赖低层模块,他们都应该依赖抽象,抽象不应该依赖于细节,细节应该依赖于抽象

针对接口编程,不要针对实现编程

使用接口和抽象类进行变量类型声明、参数类型声明、方法返回类型声明,以及数据类型的转换等,而不要用具体类来做这些事情。
引入抽象层后,系统将具有很好的灵活性,在程序中尽量使用抽象层进行编程,而将具体类写在配置文件(旧的 spring 版本中的依赖注入就是这么实现的)中,这样如果系统行为发生变化,只需要对抽象层进行过扩展,并修改配置文件,而无需修改原有系统的业务代码,在不修改的情况下完成扩展,满足开闭原则的要求。

依赖倒转是开闭原则目标的实现手段之一。

接口隔离原则

Interface Segregation Principle,ISP

客户端不应该依赖那些它不需要的接口

“接口”有两种不同含义,
一种是逻辑上的方法特征集合,
一种是Java 中的 interface

使用接口隔离原则时需要注意控制接口的粒度,接口不能太小,太小会导致系统中的接口泛滥,不利于维护;接口也不能太大,太大的接口将违背接口隔离原则,灵活性较差,使用起来很不方便。

合成复用原则

Composite Reuse Principle,CRP

优先适用对象组合,而不是通过继承来达到复用的目的

继承复用的灵活性较差,并且只能在有限的环境中使用。

通过继承来复用的主要问题在于继承复用会破坏系统的封装性,因为继承将基类的实现细节暴露给了子类,由于基类的某些内部细节对于子类来说是可见的,所以这种复用也被称为白箱复用,如果基类改变,子类也会改变。
合成复用原则可以解决上面的问题。
通过组合或聚合关系可以将已有的对象纳入到新对象中,使之成为新对象的一部分,因此新对象可以调用已有对象的功能,这样做可以使成员对象的内部实现细节对新对象不可见。

合成复用可以在运行时动态进行,新对象可以动态地引用语成员对象类型相同的其他对象。

一般情况下如果两个类之间的关系是“Has-A”时,应使用组合或聚合,如果是“Is-A”时可以使用继承。

Is-A 一个类是另一个类的“一种”;
Has-A 某一个角色具有某一项责任

迪米特法则

Law ofDemeter,LoD

每个软件单位对其他单位都只有最少的知识展现,而且局限于那些与本单位密切相关的软件单位

对软件实体之间通信的限制,迪米特法则要求限制软件实体之间的通信的宽度和深度。

在本法则中,对于一个对象,其关系对象可能体现在以下几个方面:

  • 当前对象本身
  • 以参数形式传入到当前对象方法中的对象
  • 当前对象的成员对象。
  • 如果当前对象的成员是一个集合,那么集合中的元素也都是关系对象
  • 当前对象创建的对象

满足上面条件时,对象会被认为是当前对象的“朋友”,否则就是“陌生人”

应用迪米特法则时,一个对象只能与直接朋友发生交互,不要与陌生人发生直接交互,这样做可以降低系统的耦合度,一个对象的改变不会给太多其他对象带来影响。

适当引入第三者转发这调用,同时第三者应当满足其他设计原则。