六大设计原则
目录
单一职责原则 (Single Responsibility Principle: SRP)
定义:应该有,且仅有一个原因引起类的变更 (适用范围,接口,方法,类)
“There should never be more than one reason for a class to change.”
摘录来自: . “设计模式之禅(第2版)(华章原创精品)。” Apple Books.
定义:应该有,且仅有一个原因引起类的变更 (适用范围,接口,方法,类)
建议: 对于单一职责原则,我的建议是接口一定要做到单一职责,类的设计尽量做到只有一个原因引起变化,一个方法尽可能做一件事情
单一职责的好处:
-
类的复杂性降低实现什么职责都有清晰明确的定义
-
可读性提高 (因为降低了类的复杂性)
-
可维护性提高(因为可读性提高了)
-
变更引起的风险降低:
接口的单一职责做的好,一个接口的修改只对相应的实现类有影响,对系统的拓展性与可维护性都有很大的帮助
里氏替换原则 (Liskov Substitution Principle: LSP)
定义:所有引用基类的地方必须能透明地使用其子类的对象
定义一:
“If for each object o1 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 substituted for o2 then S is a subtype of T.(如果对每一个类型为S的对象o1,都有类型为T的对象o2,使得以T定义的所有程序P在所有的对象o1都代换成o2时,程序P的行为没有发生变化,那么类型S是类型T的子类型。)”
摘录来自: . “设计模式之禅(第2版)(华章原创精品)。” Apple Books.
定义二:
“Functions that use pointers or references to base classes must be able to use objects of derived classes without knowing it.(所有引用基类的地方必须能透明地使用其子类的对象。)
第二使用者可能根本就不需要知道是父类还是子类。但是,反过来就不行了,有子类出现的地方,父类未必就能适应。”
摘录来自: . “设计模式之禅(第2版)(华章原创精品)。” Apple Books.
里氏替换原则为良好的继承定义了规范
-
子类必须完全实现父类的方法
-
“在类中调用其他类时务必要使用父类或接口,如果不能使用父类或接口,则说明类的设计已经违背了LSP原则”
-
“如果子类不能完整地实现父类的方法,或者父类的某些方法在子类中已经发生“畸变”,则建议断开父子继承关系,采用依赖、聚集、组合等关系代替继承”
-
-
子类可以有自己的个性
-
覆盖或实现父类的方法时输入参数可以被放大: 子类方法的前置条件必须与超类中被复写的方法的前置条件相同或更宽松
如果Father类的输入参数类型宽于子类的输入参数类型,会出现父类存在的地方,子类就未必可以存在,因为一旦把子类作为参数传入,调用者就很可能进入子类的方法范畴。
// 父类 public class Father { public Collection doSomething(HashMap map) { System.out.println("父类被执行..."); return map.values(); } } /** * 子类的输入参数是Map类型,也就是说子类的输入参数类型的范围扩大了 * 子类代替父类传递到调用者中,子类的方法永远都不会被执行 */ public class Son extends Father { //放大输入参数类型, 子类的方法永远不会执行 public Collection doSomething(Map map) { System.out.println("子类被执行..."); return map.values(); } } // 场景类 public class Client { public static void invoker() { //父类存在的地方,子类就应该能够存在 Father f = new Father(); //Son f = new Son(); HashMap map = new HashMap(); f.doSomething(map); } public static void main(String[] args) { invoker(); } }
Note:
宽于基类,则子类的复写方法实际为方法重载,若如参为父类方法的类型,则子类方法不会被调用到,因其直接调用了其父类的方法
“采用里氏替换原则的目的就是增强程序的健壮性,版本升级时也可以保持非常好的兼容性。即使增加子类,原有的子类还可以继续运行。在实际项目中,每个子类对应不同的业务含义,使用父类作为参数,传递不同的子类完成不同的业务逻辑,非常完美”
摘录来自: . “设计模式之禅(第2版)(华章原创精品)。” Apple Books.
-
复写或实现父类的方法时输出结果可以被缩小
父类的一个方法的返回值是一个类型T,子类的相同方法(重载或覆写)的返回值为S,那么里氏替换原则就要求S必须小于等于T,也就是说,要么S和T是同一个类型,要么S是T的子类