设计模式之6大设计原则全新解读
一.“单一职责”原则(Single Respnsibility Principle) SRP
单一职责原则的定义是:应该有且仅有一个原因引起类的变更。
单一职责原则的好处:
1、类的复杂性降低,实现什么职责都有清晰的定义;
2、可读性提高,复杂性降低,那当然可读性就提高了;
3、可维护性提高,可读性提高,那当然更容易维护了;
4、变更引起的风险降低,变更是必不可少的,如果一个接口的单一职责做得好,一个接口修改只对相应的实现类有影响,对其他的接口无影响,这对系统的扩展性、维护性都有非常大的帮助。
单一职责原则适用于接口,类,也同样适用于方法,什么意思呢?一个方法尽可能去做一件事情。比如一个方法“修改用户密码”,不要把这个方法放到“修改用户信息”方法中,这个方法的颗粒很粗。
对于单一职责,给予的建议是:接口一定要做到单一职责,类的设计尽量做到只有一个原因引起变化。
注意:单一职责原则提出了一个编写程序的标准,用“职责”或“变化原因”来衡量接口或类设计得是否优良,但是“职责”和“变化原因”都是不可度量的,因项目而异,因环境而异。
二.“里氏替换”原则(Liskvo Substitution Principle) LSP
里氏替换原则的定义是:所有引用基类的地方必须能透明地使用到其子类的对象。
里氏替换原则的好处:
1、代码共享,减少创建类的工作量,每个子类都拥有父类的方法和属性;
2、提高代码的重用性;
3、子类可以形似父类,但又异于父类,“龙生龙,凤生凤,老鼠生来会打洞”是说子拥有父的“种”,“世界上没有两片完全相同的叶子”是指明子和父的不同;
4、提高代码的可扩展性,实现父类的方法就可以“为所欲为”了,可以看到很多开源框架的扩展接口都是通过继承父类来完成的;
5、提高产品或项目的开放性;
当然继承也是有缺点的,缺点如下:
1、继承是浸入性的。只要继承,就必须拥有父类的所有属性和方法;
2、降低代码的灵活性。子类必须拥有父类的所有属性和方法,让子类自由的世界中多了些约束;
3、增强了耦合性。当父类的常量、变量和方法被修改时,必须要考虑子类的修改,而且是在缺乏规范的环境下,这种修改可能带来非常糟糕的结果----大片代码需要重构。
注意:如果子类不能完整地实现父类的方法,或者父类的某些方法在子类中已经发生“畸变”,则建议断开父子继承关系,采用依赖、聚集、组 合等关系代替继承。里氏替换原则可以正着用,但是不能反着用,在子类出现的地方,父类未必就可以胜任。
里氏替换原则为良好的继承定义了一个规范:
1、子类必须完全实现父类的方法;
2、子类可以有自己的个性;
3、覆盖或实现父类的方法时输入参数可以被放大;(子类中方法的前置条件(即传入参数类型)必须与超类中被覆写的方法的前置条件相同或更宽松)。
4、覆写或实现父类的方法时输出结果可以被缩小;
三.“依赖倒置”原则(Dependence Inversion Principle) DIP
依赖倒置原则在java语言中的表现是:
1、模块间的依赖通过抽象发生,实现类之间不能发生直接的依赖关系,其依赖关系是通过接口或抽象类产生的;
2、接口或抽象类不依赖于实现类;
3、实现类依赖接口或抽象类;
更加精简的定义就是“面向接口编程”------OOD的精髓之一。
依赖倒置原则的好处:
依赖倒置原则可以减少类间的耦合性,提高系统的稳定性,降低并行开发引起的风险,提高代码的可读性和可维护性。
要遵循依赖倒置原则,在项目开发中需要遵循的原则应该有:
1、 每一个类尽量都有接口或抽象类,或者抽象类和接口两者都具备;
2、 变量的表面类型尽量都是接口或是抽象类;
3、任何类都不应该从具体类派生(只要不超过两层的继承都是可以忍受的,特别是负责项目维护的同志,基本上可以不考虑这个原则);
4、尽量不要覆写基类的方法
5、结合里氏替换原则使用;
依赖的三种写法:
只要做到抽象依赖,即时是多层的依赖关系也无所畏惧。
1、构造函数传递依赖对象;
2、Setter方法传递依赖对象;
3、接口声明传递依赖对象;
注意:设计是否具备稳定性,只要适当地“松松土”,观察“设计的蓝图”是否还可以茁壮地成长就可以得出结论,稳定性较高的设计,在周围环境频繁发生变化的时候,依然可以做到“我自岿然不动”。
四.“接口隔离”原则(Interface Isolation)II
接口隔离原则的定义:建立单一接口,不要建立臃肿庞大的接口。
通俗说:接口尽量细化,同时接口中的方法尽量。当然说到这里,有些人会认为这与单一职责不是相同的吗?错!接口隔离原则与单一职责原则的审视角度是不同的,单一职责原则是类和接
职责单一,注重的是职责,这是业务逻辑上的划分,而接口隔离原则要求接口的方法尽量少。例如:一个接口的职责可能包含10个方法,这10个方法都放在一个接口中,并且提供给
多个模块访问,各个模块按照规定的权限来访问,在外通过文档约束“不使用的方法不要访问”,按照单一职责原则是允许的,按照接口隔离原则是不允许的,因为它要求“尽量使用
多个专门的接口”。专门的接口指的是什么?就是指提供给每个模块的都应该是单一接口,提供几个模块就应该有几个接口,而不是建立一个庞大的臃肿的接口,容纳所有的客户端访问。
接口是我们设计时对外提供的契约,通过分散定义多个接口,可以预防未来变更的扩散,提高系统的灵活性和可维护性。
保证接口的纯洁性:
接口隔离原则是对接口进行规范约束,其包含以下4层含义:
1、接口要尽量小,根据接口隔离原则拆分接口时,首先必须满足单一职责原则;
2、接口要高内聚,高内聚就是提高接口、类、模块的处理能力,减少对外的交互,要求在接口中尽量少公布public方法,接口是对外的承诺,承诺是对外的承诺,承诺越少对系统的开发越有利,变更的
风险也就越少,同时也有利于降低成本;
3、定制服务,即单独为一个个体提供优良的服务,要求只提供访问者需要的方法;
4、接口的设计是有限度的;
注意:接口隔离原则是对接口的定义,同时也是对类的定义,接口和类尽量使用原子接口或原子类来组装。
五.“迪米特”法则(Law of Demeter)LoD
迪米特法则的定义:也成最小知识原则(Least Knowledge Principle)LKP,一个对象应该对其他对象有最少的了解。
通俗说:一个类应该对自己需要耦合和调用的类知道得最少,你(被耦合或调用的类)的内部是如何复杂都和我没关系,那是你的事情,我就知道你提供的这么多public方法,我就调用这么多,其他我一概不关心。