- 信息隐藏的含义
- 为变更而设计
- 封装
- OCP
- DIP
信息隐藏的含义
需要隐藏的两种常见设计决策: 所谓要隐藏的信息, 即模块的秘密, 其实就是指对模块来说容易变化的地方, 主要分为两类
- 根据需求分配的职责, 因为需求容易变化
- 模块内部实现机制.
面向对象方法下的信息隐藏机制:
- 封装: 封装类的职责,隐藏职责的实现+预计将要发⽣的变更
- 抽象类(接口)/继承(实现): 抽象它的接口,并隐藏其内部实现
封装
封装的概念, OCP, DIP
给例子, 哪里符合哪里不符合, 哪里做得好哪里做得不好
含义:
- 将数据和行为同时包含在类中. 数据与行为互相支撑, 紧密联系
- 分离对外接口与内部实现. 接口描述类的职责, 对外公布供外界调用; 实现是类的内部实现机制, 不对外公开, 外界也不应该知道它的细节.
实现接口与实现的彻底分离: Interface抽象类, 完全分开使用
封装的实现细节:
- 封装数据和行为 → 根据声明的可见性保护类的数据和行为. 所有数据都应该是private的, 外界需要访问的数据通过getter和setter方法提供.
- 封装内部结构 → 实现中使用的复杂数据结构需要重点封装, 它们无法进行值传递, 而进行引用传递会暴露实现决策从而破坏封装.
- 封装对其他对象的引用 → 某些时候一个对象持有的其他对象的引用也需要隐藏, 以免将其意外暴露给不应该暴露给的对象
- 封装类型信息 → 隐藏具体子类, 只需要知道其公共的父类(里氏替换原则)
- 封装潜在变更 → 将预期会发生变更的地方独立为单独的类或者方法, 为其建立稳定的接口并在原类中使用, 以屏蔽潜在变更的影响.
为变更而设计
光有封装变更还不够
在开发阶段需要为将来可能的变更进行预设计, 减少维护成本
开闭原则OCP
开闭原则OCP:
- 对扩展开放
- 对修改封闭
即指在发生变更时, 好的设计不需要修改原有的代码, 只需要添加新的代码就能实现变更.
违反了OCP原则的典型标志: 出现了switch或者if-else
分⽀让程序增加复杂度,修改时容易产⽣新错误(特例: 创建)
依赖倒置原则DIP
耦合是有方向性的(A调用B / B调用A). 依赖倒置原则就关注了耦合的方向性.
依赖倒置原则DIP:
- 抽象不应依赖细节,细节应依赖抽象. 因为抽象是稳定的, 细节是不稳定的.
- ⾼层模块不应依赖低层模块, 两者都应依赖抽象. 因为抽象是稳定的, 高层和低层模块都可能是不稳定的
实现机制: 为具体类建立抽象接口并分离该接口.
具体地, 为了满足需求, 在B需要依赖于A的情况下:
- 如果A是抽象的, 那么B依赖于A就是符合DIP的
- 如果A是具体的, 那么B依赖于A就不符合DIP, 需要为A建立一个抽象接口IA, 然后让B依赖IA, A实现IA. 此时依赖关系将被倒置为B和A都依赖于IA, 这两个依赖关系都符合DIP.
DIP + 多态 → 实现OCP.
多态对于实现OCP的帮助:
- 对于新增的需求, 可以将变更后需求的实现代码组织为一个新类型, 并让新类型与程序中某个原有类型联合起来建立多态机制, 让新增代码自然链接到原有程序, 不需要修改原有代码
- 对于已有需求的变更, 可以将变更后需求的实现代码组织为一个新类型, 并将类型与其原来类型联合起来建立多态机制, 让新代码顺利替换旧代码.