- 1. 单一职责 (SOP Single Responsibility Principle)
- 2. 里氏替换(LSP Liskov Substitution Principle)
- 子类必须完全实现父类的方法
注:若子类不能完整地实现父类的方法,或者父类的某些方法在子类中已经发生“畸变”,则建议断开父子继承关系,采用依赖,聚集,组合等关系代替继承
- 子类可以有自己的个性
- 覆盖或实现父类的方法时输入参数可以被放大
方法中的输入参数为前置条件(即,契约原则,先定义出WSDL接口,制定好双方的开发协议,然后再各自实现);
里氏替换原则也要求制定一个契约,就是父类或接口。契约制定好了,也就同时制定了前置条件和后置条件,前置条件是你要我执行,就必须满足我的条件;后置条件就是我执行完了需要反馈,标准是什么;
如:与父类的方法名相同,参数不同的话,即为重载(Overload)而非覆写(Override)
若,父类方法输入的是HashMap类型,子类输入的参数是Map类型,也就是说子类输入参数类型的范围扩大了,子类替代父类传递到调用者中,子类的方法永远都不会被执行。但是,如果Father类输入的参数类型宽于子类的输入参数类型,则父类存在的地方子类未必可以存在,因为一旦把子类作为参数传入,调用者就很可能进入子类方法的范畴。
- 覆写或实现父类的方法时输出结果可以被缩小
即,父类一个方法的返回值是T,子类相同的方法(覆写或重载)的返回值为S,则里氏替换原则要求S<=T。
- 3. 依赖倒置(DIP Dependence Inversion Principle)
3.1
a.高层模块不应该依赖底层模块,两者都应该依赖其抽象
b.抽象不应该依赖细节
c.细节应该依赖抽象
3.2对象的依赖关系的三种传递方式
a. 构造函传递依赖对象
b. Setter方法传递依赖对象
c. 接口声明依赖对象(接口注入)
注:a. 每个类尽量都有接口或抽象类,或抽象类和接口两者都具备
b. 变量的表面类型尽量是接口或抽象类
c. 任何类都不应该从具体类派生
d. 尽量不要覆写基类的方法
e.结合里氏替换原则使用
4.接口隔离原则(ISP Interface Segregation Principle)
4.1接口分类
a. 实例接口(Object Interface), 即声明一个类,通过new关键字产生
b. 类接口(Class Interface) interface关键字定义的接口
4.2 接口设计原则
a. 接口要尽量小(拆分接口时,首先必须满足单一职责原则)
b. 接口要高内聚(提高接口、类、模块的处理能力,减少对外的交互)
注:在接口中尽量减少公布public方法,接口是对外的承诺,承诺越少越利于系统开发,变更的风险也越少,同时降低成本。
4.3 定制服务(只提供访问者需要的方法)
4.4 接口设计是有限度的
总结:接口隔离原则是对接口的定义,同时也是对类的定义,接口和类尽量使用原子接口或原子类来组装。
- 一个接口只服务于一个子模块或业务逻辑
- 通过业务逻辑压缩接口中public方法
- 已经被污染的接口,采用适配器模式进行转化
- 结合实际,具体应用
- 5. 迪米特法则(LOD Law of Demeter)即最少知识原则(LKP Least Knowledge Principle)
一个对象应该对其他对象有最少的了解,其核心观念:类间解耦,若耦合
- 6. 开闭原则(OCP Open Closed Principle)
定义:软件实体应对扩展开放,对修改关闭,即一个软件实体应该通过扩展来实现变化,而不是通过修改已有的代码来实现变化。软件包括:项目或软件产品中按照一定的逻辑规则划分的模块;抽象和类;方法
尽量通过扩展软件实体的行为来实现变化,而不是通过修改已有的代码来完成变化
扩展:将价格定义为int并非错误, 在非金融类项目中对货币处理时,一般取两位精度,通常的设计方法是在运算过程中扩大100倍,在需要展示时在缩小倍,减少精度带来的误差。
增加一个子类,覆写发生变化的方法,高层次的模块(即需要变化的模块static)通过新这类产生新的对象,完成业务变化对系统的最小开发。
变化可归纳为:
- 逻辑变化
- 子模块变化(会对其他模块产生影响,尤其低层次的模块必然引起高层次模块变化)
- 可见视图变化
6.1开闭原则对测试的影响
新增加一个子类,要新增加一个对应的测试类
6.1.2开闭原则可以提高复用性
6.1.3开闭原则可提高可为维护性
6.1.4面向对象开发的要求
6.2 开闭原则的具体应用
a. 抽象约束
通过接口或抽象类可以约束一组可能变化的行为,并且能够实现对扩展开放,其包含三层含义:第一,通过接口或抽象类约束扩展,对扩展进行边界限定,不允许出现在接口或抽象类中不存在的public方法;
第二,参数类型、引用对象尽量使用接口或者抽象类,而不是实现类;
第三,抽象层尽量保持稳定,一旦确定即不允许修改
b. 元数据(metadata)控制模块行为
元数据:描述环境和数据的数据,即配置参数,可以从文件中获得,也可以从数据库中获得。
- 制定项目章程
- 封装变化:第一,将相同的变化封装到一个接口或抽象类中;
第二,将不同的变化封装到不同的接口或抽象类中,不应该有两个不同的变化出现在同一个接口或抽象类中