一、单一职责原则
1. 简介
单一职责原则定义为:一个类只负责一个功能领域中的相应职责,或者定义为就一个类而言,应该只有一个引起它变化的原因。
2. 举例
客户关系管理系统中客户信息图形统计模块初始设计方案如下:

该类既包含与数据库相关的方法,如getConnection();又包含与图标生成和显示相关的方法,如createChart()和displayChart()。如果在其他类中也需要连接数据库则难以实现代码的重用。这违背单一职责原则,因此需要对该类进行拆分,使其满足单一职责原则。
重构后的结构图:

二、开闭原则
1. 简介
开闭原则的定义为:一个软件实体应当对扩展开放,对修改关闭,即软件实体应尽量在不修改原有代码的情况下进行扩展。
抽象化是开闭原则的关键。
2. 举例
多图表显示功能,用来显示饼状图、柱状图等。初始设计方案:

在ChartDisplay类中的display()方法存在如下代码片段:
1 | if (type.equals("pie")) { |
在该代码中,如果需要增加一个新的图表类,如折线图LineChart,则需要修改ChartDisplay中的display()源码,增加新的判断逻辑,这样就违反了开闭原则。
重构后结构图:

引入了抽象图表类AbstractChart,且ChartDisplay针对抽象图表类进行编程,并通过setChart()方法由客户端来设置实例化的具体图表对象,在ChartDisplay的display()方法中调用chart对象的display()方法显示图表。如果需要增加一种新的图表,如折线图LineChart,只需要将LineChart也作为AbstractChart的子类,在客户端向ChartDisplay中注入一个LineChart对象即可,无须修改现有类库的源代码。
三、里氏替换原则
1. 简介
里氏替换原则的定义为:所有引用父类的地方必须能透明地使用其子类对象。
在软件中将一个父类对象替换成它的子类对象,程序将不会产生任何错误和异常,反之不成立。
里氏替换原则是实现开闭原则的重要方式之一,由于使用父类对象的地方都可以使用子类对象,因此在程序中尽量使用父类类型来对对象进行定义,而在运行时再确定其子类类型,用子类对象来替换父类对象。
2. 举例
客户有Vip客户和普通客户,系统需给他们发送Email。原始设计方案:

发送邮件的方法send中代码重复,使用里氏替换原则进行重构。

在本实例中,在传递参数时使用基类对象,除此以外,在定义成员变量、定义局部变量、确定方法返回类型时都可使用里氏代换原则。针对基类编程,在程序运行时再确定具体子类。
四、依赖倒转原则
1. 简介
依赖倒转原则的定义为:抽象不应该依赖于细节,细节应该依赖于抽象。要针对接口编程,而不是针对实现编程。
在程序代码中传递参数时或在关联关系中,尽量引用层次高的抽象层类,即使用接口和抽象类进行变量类型声明、参数类型声明、方法返回类型声明,以及数据类型的转换等,而不要用具体类来做这些事情。
2. 举例
将Txt或Excel文件中的客户信息转存到数据库中。初始设计方案:

由于每次转换数据时数据来源不一定相同,因此需要更换数据转换类,如有时候需要将TXTDataConvertor改为ExcelDataConvertor,此时,需要修改CustomerDAO的源代码。
重构之后:

引入抽象数据转换类DataConvertor,CustomerDAO针对抽象类编程。
五、接口隔离原则
1. 简介
接口隔离原则的定义为:使用多个专门的接口,而不使用单一的总接口,即客户端不应该依赖那些它不需要的接口。
为了使接口的职责单一,需要将大接口中的方法根据其职责不同分别放在不同的小接口中,以确保每个接口使用起来都较为方便,并都承担某一单一角色。
2. 举例
数据显示模块设计原始设计方案:

dataRead()用于从文件中读取数据,方法transformToXML()用于将数据转换成XML格式,。。。
对于实现了该接口的类必须实现接口中的所有方法,而某些类只用得到其中的一两个方法,因此显得多余。
重构之后:

六、合成复用原则
1. 简介
合成复用原则的定义为:尽量使用对象组合,而不是继承来达到复用的目的。
复用时要尽量使用组合/聚合关系(关联关系),少用继承。
如果两个类之间是“Has-A”的关系应使用组合或聚合,如果是“Is-A”关系可使用继承。“Is-A”是指一个类是另一个类的一种;“Has-A”则表示某一角色具有某一项责任。
2. 举例
数据库连接设计,起初采用MySQL作为数据库,结构图:

当决定使用Oracle数据库时,需要增加一个OracleDBUtil类来连接数据库,由于CustomerDAO和DBUtil之间是继承关系,因此在更换数据库连接方式时需要修改CustomerDAO类的源码,这将违反开闭原则。
使用合成复用原则进行重构:

CustomerDAO和DBUtil之间的关系由继承关系变为关联关系,采用依赖注入的方式将DBUtil对象注入到CustomerDAO中。
七、迪米特法则
1. 简介
迪米特法则的定义为:一个软件实体应当尽可能少地与其他实体发生相互作用。
如果两个对象之间不必彼此直接通信,那么这两个对象就不应当发生任何直接的相互作用,如果其中的一个对象需要调用另一个对象的某一个方法的话,可以通过第三者转发这个调用。
2. 举例
多业务操作窗口功能,一个控件事件的触发将导致多个其他界面控件产生响应。结构图:

界面控件之间的交互关系复杂,导致在该窗口中增加新的界面控件时需要修改与之交互的其他控件的源代码,系统扩展性较差,也不便于增加和删除新控件。
