一、单一职责原则(Single Responsibility Principle,SRP)
定义:应该有且仅有一个原因引起类(接口)的变更。
理解:我们在设计接口的时候应该尽量保持一个接口只负责一种职责,类通过实现不同的接口完成不同的功能。这样,一个接口修改只对相应的实现类有影响,而不会影响到其它的类。
好处:
● 类的复杂性降低, 实现什么职责都有清晰明确的定义;
● 可读性提高, 复杂性降低, 那当然可读性提高了;
● 可维护性提高, 可读性提高, 那当然更容易维护了;
● 变更引起的风险降低, 变更是必不可少的, 如果接口的单一职责做得好, 一个接口修改只对相应的实现类有影响, 对其他的接口无影响, 这对系统的扩展性、 维护性都有非常大的帮助。
二、里氏替换原则( Liskov Substitution Principle, LSP)
继承的优点:
● 代码共享, 减少创建类的工作量, 每个子类都拥有父类的方法和属性;
● 提高代码的重用性;
● 子类可以形似父类, 但又异于父类, “龙生龙, 凤生凤, 老鼠生来会打洞”是说子拥有父的“种”, “世界上没有两片完全相同的叶子”是指明子与父的不同;
● 提高代码的可扩展性, 实现父类的方法就可以“为所欲为”了, 君不见很多开源框架的扩展接口都是通过继承父类来完成的;
● 提高产品或项目的开放性。
继承的缺点:
● 继承是侵入性的。 只要继承, 就必须拥有父类的所有属性和方法;
● 降低代码的灵活性。 子类必须拥有父类的属性和方法, 让子类自由的世界中多了些约束;
● 增强了耦合性。 当父类的常量、 变量和方法被修改时, 需要考虑子类的修改, 而且在缺乏规范的环境下, 这种修改可能带来非常糟糕的结果——大段的代码需要重构。
定义: 所有引用基类的地方必须能透明地使用其子类的对象。
理解:只要父类能出现的地方子类就可以出现, 而且替换为子类也不会产生任何错误或异常, 使用者可能根本就不需要知道是父类还是子类。 但是, 反过来就不行了, 有子类出现的地方, 父类未必就能适应。
里氏替换原则为良好的继承定义了一个规范, 一句简单的定义包含了4层含义:
1.子类必须完全实现父类的方法。(注意:在类中调用其他类时务必要使用父类或接口, 如果不能使用父类或接口, 则说明类的设计已经违背了LSP原则;如果子类不能完整地实现父类的方法, 或者父类的某些方法在子类中已经发生“畸变”, 则建议断开父子继承关系, 采用依赖、 聚集、 组合等关系代替继承。)
2.子类可以有自己的个性。(向下转型( downcast) 是不安全的,会在运行期抛出java.lang.ClassCastException异常。 从里氏替换原则来看, 就是有子类出现的地方父类未必就可以出现。)
3.覆盖或实现父类的方法时输入参数可以被放大。(子类重载父类的方法时,子类的参数范围要大于父类的参数范围。否则,子类代替父类传入到调用者中,子类的方法永远都不会执行。)
4. 覆写或实现父类的方法时输出结果可以被缩小。(父类的一个方法的返回值是一个类型T, 子类的相同方法( 重载或覆写) 的返回值为S, 那么里氏替换原则就要求S必须小于等于T, 也就是说, 要么S和T是同一个类型, 要么S是T的子类)
优点:采用里氏替换原则的目的就是增强程序的健壮性, 版本升级时也可以保持非常好的兼容性。 即使增加子类, 原有的子类还可以继续运行。 在实际项目中, 每个子类对应不同的业务含义, 使用父类作为参数, 传递不同的子类完成不同的业务逻辑, 非常完美!
三、依赖倒置原则( Dependence Inversion Principle,DIP)
定义:
● 高层模块不应该依赖低层模块, 两者都应该依赖其抽象;
● 抽象不应该依赖细节;
● 细节应该依赖抽象。
理解:高层模块和低层模块容易理解, 每一个逻辑的实现都是由原子逻辑组成的, 不可分割的原子逻辑就是低层模块, 原子逻辑的再组装就是高层模块。 那什么是抽象? 什么又是细节呢? 在Java语言中, 抽象就是指接口或抽象类, 两者都是不能直接被实例化的; 细节就是实现类, 实现接口或继承抽象类而产生的类就是细节, 其特点就是可以直接被实例化, 也就是可以加上一个关键字new产生一个对象。 依赖倒置原则在Java语言中的表现就是:
● 模块间的依赖通过抽象发生, 实现类之间不发生直接的依赖关系, 其依赖关系是通过接口或抽象类产生的;
● 接口或抽象类不依赖于实现类;
● 实现类依赖接口或抽象类。
依赖倒置原则的本质就是通过抽象( 接口或抽象类) 使各个类或模块的实现彼此独立,不互相影响, 实现模块间的松耦合, 我们怎么在项目中使用这个规则呢? 只要遵循以下的几个规则:
● 每个类尽量都有接口或抽象类, 或者抽象类和接口两者都具备
● 变量的表面类型尽量是接口或者是抽象类
● 任何类都不应该从具体类派生
● 尽量不要覆写基类的方法(如果基类是一个抽象类, 而且这个方法已经实现了, 子类尽量不要覆写。 类间依赖的是抽象, 覆写了抽象方法, 对依赖的稳定性会产生一定的影响)
● 结合里氏替换原则使用(接口负责定义public属性和方法, 并且声明与其他对象的依赖关系, 抽象类负责公共构造部分的实现, 实现类准确的实现业务逻辑, 同时在适当的时候对父类进行细化)
优点:采用依赖倒置原则可以减少类间的耦合性, 提高系统的稳定性, 降低并行开发引起的风险, 提高代码的可读性和可维护性。
六大设计原则(上)
最新推荐文章于 2020-12-05 10:39:23 发布