单一职责原则SRP(Single Responsibility Priciple)
所谓单一职责原则,指的是,一个类应该仅有一个引起它变化的原因。
这里变化的原因就是所说的“职责”,如果一个类有多个引起它变化的原因,那么也就意味着这个类有多个职责,再进一步说,就是把多个职责耦合在一起了。这会造成职责的相互影响,可能一个职责的变化,会影响到其他职责的实现,甚至引起其他职责随着变化。
里氏替换原则LSP(Liskov Substitution Principle)
所有引用基类的地方必须能透明地使用其子类的对象。通俗点讲,只要父类能出现的地方子类就可以出现,而且替换为子类也不会产生任何错误或异常,使用者可能根本就不需要知道是父类还是子类。但是,反过来就不行了,有子类出现的地方,父类未必就能适应。
里氏替换原则为良好的继承定义了一个规范,一句简单的定义包含4层含义:
子类必须完全实现父类的方法。
- 在类中调用其他类时务必要使用父类或接口,如果不能使用父类或接口,则说明类的设计已经违背了LSP原则
- 如果子类不能完整地实现父类的方法,或者父类的某些方法在子类中已经发生了”畸变”,则建议断开父子继承关系,采用依赖、聚集、组合等关系代替继承
子类可以有自己的个性
- 覆盖或实现父类的方法时输入参数可以被放大
- 覆写或实现父类的方法时输出结果可以被缩小
里式替换原则有一下两种含义:
- 里式替换原则是针对继承而言的,如果继承是为了实现代码重用,也就是为了共享方法,那么共享的父类方法就应该保持不变,不能被子类重新定义。子类只能通过新添加方法来扩展功能,父类和子类都可以实例化,而子类继承的方法和父类是一样的,父类调用方法的地方,子类也可以调用同一个继承得来的,逻辑和父类一致的方法,这时用子类对象将父类对象替换掉时,当然逻辑一致,相安无事。
- 如果继承的目的是为了多态,而多态的前提就是子类覆盖并重新定义父类的方法,为了符合LSP,我们应该将父类定义为抽象类,并定义抽象方法,让子类重新定义这些方法,当父类是抽象类时,父类就是不能实例化,所以也不存在可实例化的父类对象在程序里。也就不存在子类替换父类实例时逻辑不一致的可能。
不符合LSP的最常见的情况是,父类和子类都是可实例化的非抽象类,且父类的方法被子类重新定义,这一类的实现继承会造成父类和子类间的强耦合,也就是实际上并不相关的属性和方法牵强附会在一起,不利于程序扩展和维护。
总结一句话——就是尽量不要从可实例化的父类中继承,而是要使用基于抽象类和接口的继承。
依赖倒置原则DIP(Dependence Inversion Principle)
包含三层含义:
- 高层模块不应该依赖底层模块,两者都应该依赖其抽象
- 抽象不应该依赖细节
- 细节应该依赖抽象
在Java语言中,抽象就是指接口或抽象类,两者都是不能直接被实例化的;细节就是实现类,实现接口或继承抽象类而产生的类就是细节,其特点就是可以直接被实例化。依赖倒置原则在Java语言中的表现就是:
- 模块间的依赖通过抽象发生,实现类之间不发生直接的依赖关系,其依赖是通过接口或抽象类产生的
- 接口或抽象类不依赖于实现类
- 实现类依赖接口或抽象类
更加精简的定义就是”面向接口编程”——OOD(Object-Oriented Design,面向对象设计)的精髓之一
接口隔离原则ISP(Interface Segregation Principle)
接口隔离原则是对接口进行规范约束,其包含一下4层:
接口要尽量小
这是接口隔离原则的核心定义,不出现臃肿的接口,但是”小”是有限度的,首先就是不能违反单一职责原则。
接口要高内聚
高内聚就是提高接口、类、模块的处理能力,减少对外的交互。
定制服务
接口的设计是有限度的
接口的设计粒度越小,系统越灵活。但是灵活的同时也带来了结构的复杂化,开发难度增加,可维护性降低,所以接口设计一定要注意适度。
迪米特法则LOD(Law of Demeter)
迪米特法则(Law of Demeter, LoD)也称为最少知识原则(Least Knowledge Principle, LKP),描述的是同一个规则:一个对象应该对其他对象有最少的了解。通俗地讲,一个类应该对自己需要耦合或调用的类知道得最少。
迪米特法则对类的低耦合提出了明确的要求,其包含以下4层含义:
只和朋友交流
朋友类的定义是这样的:出现在成员变量、方法的输入输出参数中的类称为成员朋友类,而出现在方法体内部的类不属于朋友类。类与类之间的关系是建立在类间的,而不是方法间,因此一个方法尽量不引入一个类中不存在的对象,当然,JDK API提供的类除外
朋友间也是有距离的
尽量不要对外公布太多的public方法和非静态的public变量,尽量内敛,多使用private、package-private、protected等访问权限。
是自己的就是自己的
如果一个方法放在本类中,即不增加类间关系,也对本类不产生负面影响,就放置在本类中
谨慎使用Serializable
开闭原则OCP(Open-Closed Priciple)
软件实体应该对扩展开放,对修改关闭,其含义是说一个软件实体应该通过扩展来实现变化,而不是通过修改已有的代码来实现变化。软件实体包括以下几个部分:
- 项目或软件产品中按照一定的逻辑规划划分的模块
- 抽象和类
- 方法
开闭原则对扩展开放,对修改关闭,并不意味着不做任何修改,底层模块的变更,必然要有高层模块进行耦合,否则就是一个孤立无意义的代码片段。