设计模式总结
1. 一个目标
管理变化,提高复用!
2. 两种手段
分解 vs. 抽象
3. 八大原则
- 依赖倒置原则
- 开放封闭原则
- 单一职责原则
- Liskov 替换原则
- 接口隔离原则
- 对象组合优于类继承
- 封装变化点
- 面向接口编程
4. 五大技法
- 静态 -> 动态
- 早绑定 -> 晚绑定
- 继承 -> 组合
- 编译时依赖 -> 运行时依赖
- 紧耦合 -> 松耦合
5. 简单总结(重点模式加粗、次重点斜体)
- Template Method:将固定结构中变化的部分定义为虚函数,由子类去实现,即晚绑定。
- Strategy:将算法封装起来,使之可以相互替换。变"if...else..."为"虚函数"
- Observer/Event:一种“通知依赖关系”,订阅者自己订阅,通知者在需要通知的时候遍订阅者,完成消息的发送。
- Decorator:"is a" + "has a"完成对类功能的扩展,避免因继承而导致的类膨胀。is a是为了维持对外界的接口一致,has a是为了在扩展操作完毕后,调用对象真正的处理流程。其实是在其基础操作外加了一层装饰。
- Bridge:将“实现”和“业务”剥离开来,在“业务”类中包含一个执行“实现”类的指针。实现两者的解耦。如Login的逻辑操作,与平台的具体实现剥离开来,在运行时再装配。
- Factory Method:绕开new,将对象创建的工作专门的交给一个工厂来完成,延迟实例化到子类。实现对new的封装,隐藏类名,避免构造参数。
- Abstract Factory:提供一个接口负责创建一些列相关对象。如各种数据库的连接、命令和读取器对象。
- Prototype:使用Clone创建对象,用于结构复杂对象(需保留中间状态)的创建工作。如 Copy On Wirte
- Builder:模板方法在对象创建中的应用---算法结构稳定,部分元素变化。
- Facade:解耦系统内与系统外对象间的复杂关系。架构层次的模式。
- Proxy:提供一个代理封装直接使用对象的复杂性。
- Adapter:旧接口 --> 新接口。如STL中的queue、stack、deque
- Mediator:解耦系统内各对象间的关系。架构层次的模式。
- Singleton:过构造器,提供一种机制来保证一个类只有一个实例,提高性能和效率。
- Flyweight:避免大量细粒度对象的性能消耗。各种单例对象的集合,中心思想是有就给,没有才创建。
- State:解耦对象操作和状态转换间的紧耦合,与Stategy策略模式异曲同工,将状态对象化。在每次执行完操作后,需改变State,保证后续逻辑的正确运行。
- Memento:过时的模式,旨在保证封装性的同时,实现对对象状态的良好保存和恢复。如今的语言可利用序列化等方式实现上述需求,且效率更高。
- Composite:解耦客户代码与复杂的对象容器结构。本质是一个树形结构,核心在于复合节点依次遍历子节点,叶子节点则执行具体操作,对外保持接口一致。
- Iterator:实现对容器的透明遍历。更推荐用模板实现而非面向对象。(模板是编译时多态、虚函数是运行时多态,前者效率更高)
- Chain of Resposibility:解耦请求者和接受者。利用单向列表,让请求在接受链上传递直到被处理。
- Command:过时的模式,解耦“行为请求者”和“行为实现者”,将“行为”对象化,使之可以被传递、存储和组合。被C++中的函数对象所替代。
- Vistor:当子类数量确定时,解决类层次结构中行为增加的问题。核心是Double Dispatch,条件较为苛刻,使用较少。
- Interpreter:将问题表达为某种语法规则下的句子,然后构建一个解析器去解释这样的句子。如字符串的四则远算,人民币的大小写转换等。其难点是应用场合的定义。
6. Tips
- 不要为了模式而模式
- 关注抽象类&接口
- 理清变化点和稳定点
- 审视依赖变化
- 要有Framework和Application的区隔思维
- 良好的设计时演化的结果
7. 成长之路
- “手中无剑,心中无剑”:见模式而不知
- “手中有剑,心中无剑”:可以识别模式,作为应用开发人员使用模式
- “手中有剑,心中有剑”:作为框架开发人员为应用设计某些模式
- “手中无剑,心中有剑”:忘掉模式,只有原则
网友评论