第1原则:单一职责原则
单一职责原则的定义是:应该有且仅有一个原因引起类的变更。
这个原则判别起来最难的地方就是对于职责的定义,以及怎样去划分职责。
为了方便理解,举个一个简单的电话接口例子,普通人都会这样写:
public interface IPhone { // 拨通电话 public void dial(String number); // 通话 public void chat(Object o); // 通话完毕,挂电话 public void hangup(); }
初看上去没啥问题,但是它包含了两个职责:一个是协议管理,一个是数据传送。dial()和hangup()两个方法实现的是协议管理,分别负责拨号联通和挂机;chat()实现的数据的传送,把我们说的话转换成模拟信号或数字信号传递给对方,然后将对方传递过来的信号还原成我们听得懂的语言。
我们可以这样考虑,协议接通的变化会引起这个接口或实现类的变化吗?当然会的啦,那数据传送(比如电话不仅可以通话,还可以上网)的变化会引起这个接口或实现类的变化吗?当然也是会的啦。那么就有两个原因引起了这个类的变化,也就是违反了单一职责的设计原则了。
再进一步分析,这两个职责会相互影响吗?不会影响。
单一职责适用于接口、类、同时也适用于方法。就是一个方法尽可能做一件事。
最佳实践:在实际项目中,如果严格按照单一职责原则来设计系统,那么会带来过度耦合,类的数量过多,过度人为的设计了。
对于单一职责原则,最佳建议就是接口一定要做到单一职责,类的设计尽量做到只有一个原因会引起这个类的改变, 就可以了。
第2原则:里氏替换原则
大家都知道Java中继承带来的好处,大概也清楚带来的一些耦合性的坏处吧。所以,组合优于继承
究竟什么时候最适合用继承呢?里氏替换定义是:所有引用基类的地方必须能透明地使用其子类的对象。
包含四层含义:
1,子类必须完全实现父类的方法
注意:如果子类不能完整实现父类方法,或者父类的某些方法在子类中已经发生畸变,则建议断开父子继承关系,采用依赖、聚集、组合等关系代替继承。
2,子类可以由自己的个性
也就是说上面的反过来就不一定成立了,有子类出现的地方父类未必就可以出现
3,覆盖或实现父类方法时输入参数可以被放大
比如父类的一个方法 do(HashMap map) ,子类中定义 do(Map map),这个就是重载overload,而不是override。那么无论是用Map引用或者HashMap引起去调用子类的方法,都只会执行父类方法,子类的参数可以运行范围扩大了,但是只要是父类出现的地方,就可以替换成子类这个原则使然,执行结果不变。
所以子类中方法的前置条件必须与超类中被覆写的方法的前置条件相同或者更宽松。
4,赋写或实现父类的方法时输出结果可以被缩小
第3原则:依赖倒置原则
三层含义:
1,高层模块不应该依赖低层模块,两者都应该依赖抽象
2,抽象不应该依赖细节
3,细节应该依赖抽象
更为精确一点就是面向接口编程 ---OOD Object-Oriented Design 面向对象编程的精髓之一。
采用依赖倒置原则可以减少类间的耦合性,提高系统的稳定性,减低并行开发引起的风险,提高代码的可读性和可维护性,最后一点,貌似还可以提高代码的可测性。
被依赖者的变更竟然让依赖者来承担修改的成本,这样的依赖关系谁肯承担,这个设计是极其不稳定的。
最佳实践:
1,每个类尽量都有接口或抽象类,或者抽象类和接口两者都具备
2,变量的表面类型尽量使接口或者是抽象类
3,任何类都不应该从具体类派生
4,尽量不要覆写基类方法
5,结合里氏替换原则使用
接口负责定义public属性和方法,并且声明与其他对象的依赖关系,抽象类负责公共构造部分的实现,实现类准确的实现业务逻辑,同时在适当的时候对父类进行细化。
第4原则:接口隔离原则
1,客户端不应该依赖它不需要的接口
2,类间的依赖关系应该建立在最小的接口上
总之就是要将接口细化,保证其纯洁性
接口隔离跟单一职责原则是不同的,单一职责原则是从业务逻辑上划分的,要求类和接口职责单一,注重的是职责,而接口隔离原则要求接口方法尽量少。
根据接口隔离原则拆分接口时,首先必须满足单一职责原则。
最佳实践:
1,通过业务逻辑压缩接口中的public方法,接口时常去回顾,尽量让接口达到满身筋骨肉
2,已经被污染了的接口,要大胆的去修改,如果变更的风险大,则采用适配器模式进行转化处理
第5原则:迪米特法则 Law of Demeter
也称为最小知识原则:一个对象应该对其他对象有最少的了解,别人的私事,你知道的越少越好。
出现在成员变量、方法的输入输出参数中的类称为成员朋友类,而出现在方法体内部的类不属于朋友类,迪米特法则告诉我们,一个类只应该与成员朋友类交流,而不应该在方法体内部再去依赖其他的非朋友类。
第6原则:开闭原则
一个软件实体如类、模块、函数应该对扩展开放,对修改关闭
其含义是说,一个软件实体应该通过扩展来实现变化,而不是通过修改已有的代码来实现变化。
当业务需求变更时,尽量修改高层次模块,防止底层模块的修改。
本人博客已搬家,新地址为:http://yidao620c.github.io/