状态与命令模式 State and Command Patterns
状态模式 State Pattern
- 模式动机
- 一个对象的行为取决于一个或多个动态变化的属性,这样的属性叫做状态,这样的对象叫做有状态的对象,这样的对象状态是从事先定义好的一些列值中取出的。当一个这样的对象与外部事件产生互动时,其内部状态就会改变,从而使得系统的行为也随之发生变化
- 模式定义
- 状态模式允许一个对象在其内部状态 internal state 改变时改变它的行为,对象看起来似乎修改了它的类,其别名为状态对象,状态模式是一种对象行为型模式
- 模式结构
- Context 环境类
- State 抽象状态类
- ConcreteState 具体状态类

- 分析
- 状态模式描述了对象状态的变化以及对象如何在每一种状态下表现出不同的行为
- 状态模式的关键是引入了一个抽象类来专门表示对象的状态,这个类叫做抽象状态类,而对象的每一种具体状态类都继承了该类,并在不同具体状态类中实现了不同状态的行为,包括各种状态之间的切换
- 环境类实际上就是拥有状态的对象,环境类有时候可以充当状态管理器的角色,可以在环境类中对状态进行切换操作
- 状态类的产生是由于环境类存在多个状态,同时还满足两个条件:这些状态经常需要切换,在不同的状态下对象的行为不同。因此可以将不同对象下的行为单独提取出来封装在具体的状态类中,使得环境类对象在其内部状态改变时可以改变它的行为,对象看起来似乎修改了它的类,而实际上是由于切换到不同的具体状态类实现的
- 优缺点
- 优点
- 封装了转换规则
- 枚举可能的状态
- 将所有与某个状态有关的行为放到一个类中,并且可以方便地增加新的状态,只需要改变对象状态即可改变对象的行为
- 允许状态转换逻辑与状态对象合成一体
- 可以让多个环境对象共享一个状态对象
- 缺点
- 增加系统类和对象的个数
- 如果使用不当将导致程序结构和代码的混乱
- 对开闭模式的支持并不太好
- 优点
- 模式适用环境
- 对象的行为依赖于它的状态并且可以根据它的状态改变而改变它的相关行为
- 代码中包含大量与对象状态有关的条件语句
- 模式应用
- 工作流对象
- 游戏角色的控制
- 模式扩展
- 共享状态
- 多个环境对象需要共享同一个状态,如果希望在系统中实现多个环境对象实例共享一个或多个状态对象,那么需要将这些状态对象定义为环境的静态对象成员
- 简单状态模式
- 状态都相互独立,状态之间无须进行转换的状态模式
- 遵循开闭原则,在客户端可以针对抽象状态类进行编程
- 可切换状态的状态模式
- 需要调用环境类Context的setState()方法进行状态的转换操作,增加新的状态类可能需要修改到其他状态类甚至环境类的源代码
- 共享状态
命令模式 Command Pattern
- 模式动机
- 需要向某些对象发送请求,但是并不知道请求的接收者是谁,也不知道被请求的操作是哪个,我们只需在程序运行时指定具体的请求接收者即可,可以使用命令模式来使得请求发送者与请求接收者消除彼此之间的耦合
- 命令模式可以对发送者和接收者完全解耦,发送者与接收者之间没有直接引用关系,发送请求的对象只需要知道如何发送请求,而不必知道如何完成请求
- 模式定义
- 将一个请求封装为一个对象,从而使我们可用不同的请求对客户进行参数化;对请求排队或者记录请求日志,以及支持可撤销的操作,是一种对象行为型模式,其别名是动作模式 Action Pattern 或事务模式 Transaction Pattern
- 模式结构
- Command 抽象命令类
- ConcreteCommand 具体命令类
- Invoker 调用者
- Receiver 接收者
- Client 客户类

- 模式分析
- 命令模式的本质是对命令进行封装,将发出命令的责任和执行命令的责任分割开
- 请求的一方发出请求,要求执行一个操作;接收的一方收到请求,并执行操作
- 命令模式允许请求的一方和接收的一方独立开来,使得请求的一方不必知道接收请求的一方的接口
- 命令模式使请求本身成为一个对象,这个对象和其他对象一样可以被存储和传递
- 命令模式的关键在于引入了抽象命令接口,且发送者针对抽象命令接口编程,只有实现了抽象命令接口的具体命令才能与接受者相关联
- 模式优缺点
- 优点
- 降低系统的耦合度
- 新的命令可以很容易地加入到系统中
- 可以比较容易地设计一个命令队列和宏命令(组合命令)
- 可以方便地实现对请求的Undo和Redo
- 缺点
- 使用命令模式可能会导致某些系统有过多的具体命令类
- 优点
- 适用环境
- 系统需要将请求调用者和请求接收者解耦
- 系统需要在不同的时间指定请求,将请求排队和执行请求
- 系统需要支持命令的撤销操作和恢复操作
- 系统需要将一组操作组合在一起,即支持宏命令
- 模式应用
- GUI的委派事件模型
- UNIX平台下的Shell编程
- 模式扩展
- 撤销操作

- 宏命令(组合命令) 命令模式和组合模式联用的产物
- 在调用宏命令的execute()方法时,将递归调用它所包含的每个成员命令的execute()方法
- 撤销操作

高频英文术语 Glossary
| English Term | 中文 | 备注 |
|---|---|---|
| State Pattern | 状态模式 | 对象内部状态改变时改变行为 |
| State | 抽象状态 | 定义状态相关行为接口 |
| ConcreteState | 具体状态 | 实现某一状态下的行为和转换 |
| Context | 环境类 | 拥有状态的对象 |
| Internal State | 内部状态 | 决定对象行为的状态 |
| State Transition | 状态转换 | 从一个状态切换到另一个状态 |
| Transition Rule | 转换规则 | 当前状态 + 操作 = 下一个状态 |
| Shared State | 共享状态 | 多个环境对象共享同一状态对象 |
| Static Member | 静态成员 | 属于类,所有对象共享 |
| Command Pattern | 命令模式 | 将请求封装成对象 |
| Command | 抽象命令 | 声明 execute() 等接口 |
| ConcreteCommand | 具体命令 | 绑定 Receiver 并实现请求 |
| Invoker | 调用者 / 请求发送者 | 触发命令执行 |
| Receiver | 接收者 | 真正执行业务操作 |
| Client | 客户端 | 创建并组装命令、接收者和调用者 |
| execute | 执行 | 命令对象的执行方法 |
| Undo | 撤销 | 执行反操作 |
| Redo | 重做 | 重新执行被撤销命令 |
| Command Queue | 命令队列 | 将命令排队后执行 |
| Macro Command / Composite Command | 宏命令 / 组合命令 | 一个命令包含多个子命令 |