设计模式 - 行为型模式 | 青训营笔记

61 阅读6分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 23 天

行为型模式

  • 行为型模式定义了系统中对象之间的交互与通信,研究系统在运行时的相互通信与协作,进一步明确对象的职责,包括对对象复杂的流程的控制

命令模式

定义:将一个请求封装为一个对象,从而使我们对不同的请求对客户进行参数化;对请求排队或者记录请求日志,以及支持可撤销的操作

类图:

命令模式

分析:

  • 命令模式是对请求进行的封装
  • 请求的发送者和接收者,完全解耦
  • 使得请求的一方不必知道接受请求一方的接口,更不必关心发出请求的具体操作流程
  • 发送者只需要关心如何发出请求,不关心请求如何完成
  • 一个请求对应一个命令

优点:

  • 降低系统的耦合度
  • 新的命令很容易被添加到新的系统中,符合开闭原则
  • 比较容易去实现一个命令队列或者宏命令(组合命令)
  • 为请求的**撤销(Ctrl-Z)和恢复(Ctrl-Y)**提供了一种设计和实现方案

缺点:

  • 可能会导致系统有过多的具体命令类

场景:

  • 将请求者和接收者解耦
  • 在不同时间指定请求、将请求排队和执行请求
  • 需要支持**撤销(Undo)和恢复(Redo)**操作
  • 需要将一组命令组合形成宏命令

迭代器模式

动机:迭代器用于对一个聚合对象进行遍历,将遍历操作从聚合对象中分离出来,聚合对象只负责存储数据,而遍历数据由迭代器来完成。访问一个聚合对象中的元素,但是又不需要暴露它的内部结构,那么就需要迭代器模式

定义:提供一种方法来访问聚合对象,而不用暴露这个聚合对象的内部表示

类图:

迭代器模式

分析:

  • 聚合对象的职责
    • 存储数据:最基础的职责
    • 遍历数据:既可以是变化的,又是可以分离的
  • 将遍历数据的行为从聚合对象中分离出来,封装到迭代器中,简化聚合对象的设计,符合单一职责原则

优点:

  • 以不同的方式遍历一个聚合对象,在同一个聚合对象上可以定义多种遍历方式
  • 简化了聚合对象
  • 无论是增加新的聚合类,还是增加新的迭代器都很方便,符合开闭原则

缺点:

  • 类的个数成对增加,增加了整个系统的复杂性
  • 抽象迭代器的设计难度大,需要充分考虑到系统将来的扩展。设计一个考虑全面的抽象迭代器并不是一件容易的事情

情景:

  • 访问聚合对象本身但是不能暴露内部结构
  • 需要提供聚合对象的多种遍历方式
  • 为遍历提供一个统一的接口,客户端可以一致性操作

观察者模式

别名:

  • 发布订阅模式
  • 模型-视图模式
  • 源-监听器模式
  • 从属模式

动机:

  • 软件系统:一个对象状态的改变,可能会导致其他对象的状态改变,他们之间将会发生联动关系
  • 发生改变的对象叫做观察目标(Subject), 被通知的对象叫做观察者(Observer)

定义:定义对象之间的一种一对多的依赖关系,使得每当一个对象的状态发生改变时,其相关依赖的对象皆得到通知并且被自动更新

类图:

观察者模式

分析:

  • 有时候在具体的观察者类中需要使用到具体的目标类中的状态,会存在关联关系
  • 如果在具体层存在关联关系,那么系统的扩展性将会受到一定影响,违背开闭原则。如果原有的观察者类无需关联新增的具体目标,则系统扩展性不受影响。

优点:

  • 实现表现层和数据层的分离
  • 目标类和观察者之间建立一个抽象的耦合
  • 支持广播通信
  • 符合开闭原则

缺点:

  • 将所有的观察者通知到会花费很多时间
  • 如果存在循环依赖将会导致系统奔溃
  • 没有相应的机制让观察者观察到所观察的目标的变化过程

场景:

  • 抽象模型有两方面,一个方面依赖于另一个方面
  • 一个对象的改变将导致或者多个其他对象发生改变,并且不知道有多少对象会改变,也不知道这些对象的具体目标
  • 需要创建一个触发链

状态模式

动机:

  • 软件系统中
    • 有些对象有很多的状态
    • 这些状态在一定条件下能够转换
    • 对象在不同的状态下有不同的行为

定义:允许一个对象在其内部状态改变时改变其行为,在外界看来似乎是改变了它的类

类图:

状态模式

分析:

  • 复杂对象的状态转换以及不同状态下的封装问题
  • 将一个对象的状态从对象中分离出来,封装到专门的状态类中
  • 客户端无需关心对象状态的转换,以及对象当前所处的状态

优点:

  • 封装了状态转换规则,可以对状态转换代码集中管理
  • 将所有与某个状态有关的行为封装到一个类中
  • 允许将状态转换的逻辑和对象合成一体,而不是提供一个巨大的条件语句块
  • 多个环境对象共享一个状态对象,从而减少系统中对象的个数

缺点:

  • 增加系统中对象的个数
  • 结构和实现较为复杂,如果使用不当很容易导致程序结构和代码混乱,增加设计难度
  • 对开闭原则支持差,状态之间依赖于具体的实现,如果状态规则修改,也需要修改对应的源代码

场景:

  • 对象的行为依赖于状态,状态的改变导致行为的改变
  • 在代码中大量包含与状态有关的条件语句

策略模式

动机:实现目标的途径很多的时候,就需要根据实际情况选择更加合适的途径。使用硬编码实现将导致系统违背开闭原则,扩展困难,维护困难

定义:定义一系列算法,将每一个算法封装到策略类中,并且让他们可以相互替换

类图:

策略模式

分析:

  • 算法可以独立于使用它的客户而变化
  • 策略模式提供了一种可插入式(Pluggable)算法的实现方案

优点:

  • 对开闭原则的完美支持
  • 提供了管理相关算法的方案
  • 提供了一种可以替换继承关系的方案
  • 可以避免多重条件选择
  • 提供了一种算法的复用机制,在不同的环境类可以方便地复用策略类

缺点:

  • 客户端必须知道所有的策略类
  • 将造成系统产生大量策略类
  • 无法在客户端同时使用多个策略类

情景:

  • 动态选择算法中的一种
  • 避免难以维护的多重条件选择语句
  • 提高算法的保密性和安全性