这是我参与「第五届青训营 」伴学笔记创作活动的第 23 天
行为型模式
- 行为型模式定义了系统中对象之间的交互与通信,研究系统在运行时的相互通信与协作,进一步明确对象的职责,包括对对象复杂的流程的控制
命令模式
定义:将一个请求封装为一个对象,从而使我们对不同的请求对客户进行参数化;对请求排队或者记录请求日志,以及支持可撤销的操作
类图:
分析:
- 命令模式是对请求进行的封装
- 请求的发送者和接收者,完全解耦
- 使得请求的一方不必知道接受请求一方的接口,更不必关心发出请求的具体操作流程
- 发送者只需要关心如何发出请求,不关心请求如何完成
- 一个请求对应一个命令
优点:
- 降低系统的耦合度
- 新的命令很容易被添加到新的系统中,符合开闭原则
- 比较容易去实现一个命令队列或者宏命令(组合命令)
- 为请求的**撤销(Ctrl-Z)和恢复(Ctrl-Y)**提供了一种设计和实现方案
缺点:
- 可能会导致系统有过多的具体命令类
场景:
- 将请求者和接收者解耦
- 在不同时间指定请求、将请求排队和执行请求
- 需要支持**撤销(Undo)和恢复(Redo)**操作
- 需要将一组命令组合形成宏命令
迭代器模式
动机:迭代器用于对一个聚合对象进行遍历,将遍历操作从聚合对象中分离出来,聚合对象只负责存储数据,而遍历数据由迭代器来完成。访问一个聚合对象中的元素,但是又不需要暴露它的内部结构,那么就需要迭代器模式
定义:提供一种方法来访问聚合对象,而不用暴露这个聚合对象的内部表示
类图:
分析:
- 聚合对象的职责
- 存储数据:最基础的职责
- 遍历数据:既可以是变化的,又是可以分离的
- 将遍历数据的行为从聚合对象中分离出来,封装到迭代器中,简化聚合对象的设计,符合单一职责原则
优点:
- 以不同的方式遍历一个聚合对象,在同一个聚合对象上可以定义多种遍历方式
- 简化了聚合对象
- 无论是增加新的聚合类,还是增加新的迭代器都很方便,符合开闭原则
缺点:
- 类的个数成对增加,增加了整个系统的复杂性
- 抽象迭代器的设计难度大,需要充分考虑到系统将来的扩展。设计一个考虑全面的抽象迭代器并不是一件容易的事情
情景:
- 访问聚合对象本身但是不能暴露内部结构
- 需要提供聚合对象的多种遍历方式
- 为遍历提供一个统一的接口,客户端可以一致性操作
观察者模式
别名:
- 发布订阅模式
- 模型-视图模式
- 源-监听器模式
- 从属模式
动机:
- 软件系统:一个对象状态的改变,可能会导致其他对象的状态改变,他们之间将会发生联动关系
- 发生改变的对象叫做观察目标(Subject), 被通知的对象叫做观察者(Observer)
定义:定义对象之间的一种一对多的依赖关系,使得每当一个对象的状态发生改变时,其相关依赖的对象皆得到通知并且被自动更新
类图:
分析:
- 有时候在具体的观察者类中需要使用到具体的目标类中的状态,会存在关联关系
- 如果在具体层存在关联关系,那么系统的扩展性将会受到一定影响,违背开闭原则。如果原有的观察者类无需关联新增的具体目标,则系统扩展性不受影响。
优点:
- 实现表现层和数据层的分离
- 目标类和观察者之间建立一个抽象的耦合
- 支持广播通信
- 符合开闭原则
缺点:
- 将所有的观察者通知到会花费很多时间
- 如果存在循环依赖将会导致系统奔溃
- 没有相应的机制让观察者观察到所观察的目标的变化过程
场景:
- 抽象模型有两方面,一个方面依赖于另一个方面
- 一个对象的改变将导致或者多个其他对象发生改变,并且不知道有多少对象会改变,也不知道这些对象的具体目标
- 需要创建一个触发链
状态模式
动机:
- 软件系统中
- 有些对象有很多的状态
- 这些状态在一定条件下能够转换
- 对象在不同的状态下有不同的行为
定义:允许一个对象在其内部状态改变时改变其行为,在外界看来似乎是改变了它的类
类图:
分析:
- 复杂对象的状态转换以及不同状态下的封装问题
- 将一个对象的状态从对象中分离出来,封装到专门的状态类中
- 客户端无需关心对象状态的转换,以及对象当前所处的状态
优点:
- 封装了状态转换规则,可以对状态转换代码集中管理
- 将所有与某个状态有关的行为封装到一个类中
- 允许将状态转换的逻辑和对象合成一体,而不是提供一个巨大的条件语句块
- 多个环境对象共享一个状态对象,从而减少系统中对象的个数
缺点:
- 增加系统中对象的个数
- 结构和实现较为复杂,如果使用不当很容易导致程序结构和代码混乱,增加设计难度
- 对开闭原则支持差,状态之间依赖于具体的实现,如果状态规则修改,也需要修改对应的源代码
场景:
- 对象的行为依赖于状态,状态的改变导致行为的改变
- 在代码中大量包含与状态有关的条件语句
策略模式
动机:实现目标的途径很多的时候,就需要根据实际情况选择更加合适的途径。使用硬编码实现将导致系统违背开闭原则,扩展困难,维护困难。
定义:定义一系列算法,将每一个算法封装到策略类中,并且让他们可以相互替换。
类图:
分析:
- 算法可以独立于使用它的客户而变化
- 策略模式提供了一种可插入式(Pluggable)算法的实现方案
优点:
- 对开闭原则的完美支持
- 提供了管理相关算法的方案
- 提供了一种可以替换继承关系的方案
- 可以避免多重条件选择
- 提供了一种算法的复用机制,在不同的环境类可以方便地复用策略类
缺点:
- 客户端必须知道所有的策略类
- 将造成系统产生大量策略类
- 无法在客户端同时使用多个策略类
情景:
- 动态选择算法中的一种
- 避免难以维护的多重条件选择语句
- 提高算法的保密性和安全性