1.1 6大设计原则简介
6大设计原则包括:单一职责原则、里氏替换原则、依赖倒置原则、接口隔离原则、迪米特法则和开闭原则。
1.2 单一职责原则
单一职责原则(single responsibility principle),这个原则存在着争议,争议之处就在于对职责的定义,什么是类的职责,以及怎么划分类的职责。先举例分析一下:
只要做过项目,肯定要接触到用户、机构、角色这些模块,基本上使用的都是RBAC模式(Role-Based Access Control,基于角色来完成用户权限的授予和取消,是动作主体(用户)与资源的行为(权限)分离),确实是一个很好的解决方法。我们在这里要讲的是用户管理、修改用户的信息、增加机构(一个人属于多个机构)、增加角色等,用户有这么多的信息和行为要维护,我们就把这些写到一个接口中,都是用户管理类。
单一职责原则的好处:
类的复杂性降低,实现什么职责都有清晰明确的定义:
可读性提高,复杂性降低,那当然可读性提高了:
可维护性提高,可读性提高,那当然更容易维护了:
变更引起的风险降低,变更时必不可少的,如果接口的单一职责做得好,一个接口修改支队相应的实现类有影响,对其他的接口无影响,这对系统的扩展性、维护性都有非常大的帮助。
注意:单一职责原则提出了一个编写程序的标准,用“职责“或者“变化原因”来衡量接口或类设计是否优良,但是“职责”和“变化原因”都是不可度量的,因项目而异,因环境而异。
对于单一职责原则,建议是接口一定要做到单一职责,类的设计尽量做到只有一个原因引起变化。
1.3 里氏替换原则
在面向对象的语言中,继承是必不可少的、非常优秀的语言机制,优点如下:
继承的缺点:
java中使用extends关键字来实现继承,它采用了单一继承的规则,C++则采用了多重继承的规则,一个子类可以继承多个父类。从整体上来看,利大于弊,怎么才能让“利”的元素发挥最大的作用,同时减少“弊”带来的麻烦呢?解决方案是引入里氏替换原则(liskov substitute principle LSP),
里氏替换定义:
第一种定义(也是最正宗的定义):if for each object 01 of type S there is an object o2 of type T such that for all programs P defined in terms of T ,the behavior of P is unchanged when o1 is substitue for o2 then S is a subtype of T(如果对每一个类型为S 的对象o1,都有类型为T的对象o2,使得以T定义的所有程序P在所有的对象o2被替换为o1时,程序P的行为没有发生变化,那么类型S是类型T的子类型。)
第二种定义:所有引用积累的地方必须能透明地使用其子类的对象。
第二个定义式最清晰明确的,通俗讲,只要父类能出现的地方子类就可以出现,而且替换为子类也不会产生任何错误或者异常,使用者可能根本就不需要知道是父类还是子类。但是反过来就不行了,有子类出现的地方,父类未必就能适应。
里氏替换原则为良好的继承定义了一个规范,一句简单的定义包含了4层含义。
在项目中,采用里氏替换原则时,尽量避免子类的“个性”,一旦子类有“个性”,这个子类和父类之间的关系就很难调和了,把子类当做父类使用,子类的“个性“被抹杀——委屈了点;把子类单独作为一个业务来使用,则会让代码间的耦合关系变得扑朔迷离——缺乏类替换的标准
1.4 依赖倒置原则
依赖倒置原则(dependence inversion principle)包含三层含义:
高层模块和底层模块容易理解,每一个逻辑的实现都是由原子逻辑组成的,不可分割的原子逻辑就是底层模块,原子逻辑的在组装就是高层模块。那什么是抽象?什么是细节?在java语言中,抽象就是指接口或抽象类,两者都是不能直接被实例化的:细节就是实现类,实现接口或集成抽象类而产生的类就是细节,其特点就是可以直接被实例化,也就是可以加上一个关键字new产生一个对象。依赖倒置原则在java语言中的表现就是:
更加精简的定义就是“面向接口编程”——OOD(Object-oriented design,面向对象设计)的精髓之一。
依赖倒置原则的本质就是通过抽象(接口或抽象类)使各个类或模块的实现彼此独立,不互相影响,实现模块间的松耦合,我们怎么在项目中使用这个规则呢?只要遵循以下的几个规则就可以:
依赖倒置原则时6个设计原则中最难以实现的原则,它是实现开闭原则的重要途径。依赖倒原则没有实现,就别想实现对拓展开放,对修改关闭。在项目中,大家只要记住是“面向接口编程”就基本上抓住了依赖倒置原则的核心。
1.5 接口隔离原则
接口隔离原则要求接口的纯洁性,接口隔离原则时对接口进行规范约束,包含4层含义:
实践中根据以下几个规则来衡量:
1.6 迪米特法则
迪米特法则(law of demeter,LoD)也成为最少知识原则(least knowledge principle),虽然名字不同,但描述的是同一个规则:一个对象应该对其他对象有最少的了解。通俗地讲,一个类应该对自己需要耦合或调用的类知道得最少,你(被耦合或调用的类)的内部是如何复杂都和我没有关系,那是你的事情,我就知道提供的这么多public方法,我就调用这么多,其他的我一概不关心。
迪米特法则的核心观念就是类间解耦,弱耦合,只有弱耦合了以后,类的复用率才可以提高。其要求的结果就是产生了大量的中转和跳转类,导致系统的复杂性提高,同时也为维护带来了难度。需要反复权衡,既做到结构清晰,又做到高内聚低耦合。
1.7 开闭原则
开闭原则定义:一个软件实体如类、模块和函数应该对扩展开放,对修改关闭。
开闭原则的的重要性:
如何使用开闭原则?
开闭原则时一个很虚的原则,前面5个原则都是对开闭原则的具体解释。但是开闭原则并不局限于这么多,它“虚”地没有边界。
如何在实际工作中应用这个“虚”的像口号的原则:
本文内容参考《设计模式之禅(第二版)》作者:琴小波