Appearance
状态模式(State Pattern)笔记
定义
状态模式是一种行为设计模式,它允许一个对象在其内部状态改变时改变它的行为,使对象看起来似乎修改了它的类。
英文原文定义:
The State Pattern allows an object to alter its behavior when its internal state changes. The object will appear to change its class.
核心概念
状态模式通过将不同状态的行为封装到独立的类中,并将状态委托给当前状态对象,使得状态转换更加清晰,避免了复杂的条件判断语句。
主要角色
- Context(上下文):维护一个ConcreteState子类的实例,定义当前状态
- State(状态接口):定义一个接口,封装与Context的特定状态相关的行为
- ConcreteState(具体状态):实现State接口,每个子类实现一个与Context状态相关的行为
优缺点
优点
- 消除条件语句:用多态代替大量条件判断
- 单一职责原则:将与特定状态相关的代码放在独立类中
- 开闭原则:容易新增状态而不修改已有代码
- 状态转换显式化:使状态转换更加明确和可控
- 状态对象复用:可以共享无实例变量的状态对象
缺点
- 类数量增加:每个状态都需要一个类
- 过度设计风险:简单状态机使用此模式可能增加复杂度
- 上下文耦合:状态子类可能依赖上下文实现
- 性能开销:状态转换可能带来额外对象创建开销
解决的问题
状态模式主要解决以下经典问题:
- 复杂状态逻辑:对象行为依赖于它的状态,并且必须在运行时根据状态改变行为
- 条件语句膨胀:操作中含有大量与对象状态有关的条件语句
- 状态转换混乱:当状态转换逻辑分散在多个方法中时
- 状态共享需求:当需要多个上下文实例共享状态对象时
实现注意事项
状态转换位置:
- 由上下文决定(集中管理)
- 由状态类决定(分散管理)
状态对象创建:
- 按需创建(每次转换时创建)
- 预先创建(所有状态单例)
状态存储:
- 上下文存储全部状态数据
- 状态对象存储部分状态数据
线程安全:
- 无状态的状态对象可以共享
- 有状态的状态对象需要实例化
初始化状态:
- 确保上下文始终有有效状态
- 考虑使用Null Object模式处理未知状态
实现变体
状态驱动转换:
- 状态类知道并决定下一个状态
- 转换逻辑分散在各状态类中
表驱动转换:
- 使用转换表定义状态转换规则
- 更加集中和可配置
状态模式+享元:
- 无状态的状态对象作为享元共享
- 适合大量上下文实例场景
状态模式+组合:
- 构建层次状态结构
- 支持状态继承和复用
与其他模式的关系
相似模式区分
策略模式:
- 状态:状态知道其他状态,可触发状态转换
- 策略:策略通常不知道其他策略
命令模式:
- 状态:封装与状态相关的行为
- 命令:封装操作请求
职责链模式:
- 状态:状态处理请求后可改变上下文状态
- 职责链:请求沿链传递直到被处理
常见搭配组合
- 状态 + 享元:共享无状态的状态对象
- 状态 + 单例:状态对象作为单例
- 状态 + 组合:构建层次状态机
- 状态 + 观察者:状态变化时通知观察者
典型应用场景
- 订单状态管理(待支付、已支付、已发货等)
- 工作流引擎
- 游戏角色状态(站立、行走、奔跑等)
- TCP连接状态(建立连接、数据传输、关闭连接)
- 电梯控制系统
- 自动售货机
- UI组件状态(启用、禁用、悬停等)
代码示例(电梯状态实现)
java
// 状态接口
interface ElevatorState {
void openDoors();
void closeDoors();
void move();
void stop();
}
// 具体状态:停止状态
class StoppedState implements ElevatorState {
private Elevator elevator;
public StoppedState(Elevator elevator) {
this.elevator = elevator;
}
@Override
public void openDoors() {
System.out.println("Opening doors");
elevator.setState(elevator.getDoorsOpenState());
}
@Override
public void closeDoors() {
System.out.println("Doors already closed");
}
@Override
public void move() {
System.out.println("Starting movement");
elevator.setState(elevator.getMovingState());
}
@Override
public void stop() {
System.out.println("Already stopped");
}
}
// 具体状态:门开状态
class DoorsOpenState implements ElevatorState {
private Elevator elevator;
public DoorsOpenState(Elevator elevator) {
this.elevator = elevator;
}
@Override
public void openDoors() {
System.out.println("Doors already open");
}
@Override
public void closeDoors() {
System.out.println("Closing doors");
elevator.setState(elevator.getStoppedState());
}
@Override
public void move() {
System.out.println("Cannot move with doors open");
}
@Override
public void stop() {
System.out.println("Already stopped with doors open");
}
}
// 具体状态:移动状态
class MovingState implements ElevatorState {
private Elevator elevator;
public MovingState(Elevator elevator) {
this.elevator = elevator;
}
@Override
public void openDoors() {
System.out.println("Cannot open doors while moving");
}
@Override
public void closeDoors() {
System.out.println("Doors already closed while moving");
}
@Override
public void move() {
System.out.println("Already moving");
}
@Override
public void stop() {
System.out.println("Stopping elevator");
elevator.setState(elevator.getStoppedState());
}
}
// 上下文:电梯
class Elevator {
private ElevatorState stoppedState;
private ElevatorState doorsOpenState;
private ElevatorState movingState;
private ElevatorState currentState;
public Elevator() {
stoppedState = new StoppedState(this);
doorsOpenState = new DoorsOpenState(this);
movingState = new MovingState(this);
currentState = stoppedState;
}
public void setState(ElevatorState state) {
this.currentState = state;
}
// 委托给当前状态
public void openDoors() {
currentState.openDoors();
}
public void closeDoors() {
currentState.closeDoors();
}
public void move() {
currentState.move();
}
public void stop() {
currentState.stop();
}
// 获取具体状态
public ElevatorState getStoppedState() {
return stoppedState;
}
public ElevatorState getDoorsOpenState() {
return doorsOpenState;
}
public ElevatorState getMovingState() {
return movingState;
}
}
// 客户端代码
public class ElevatorTest {
public static void main(String[] args) {
Elevator elevator = new Elevator();
elevator.openDoors(); // 从停止到开门
elevator.closeDoors(); // 从开门到停止
elevator.move(); // 从停止到移动
elevator.stop(); // 从移动到停止
elevator.openDoors(); // 从停止到开门
}
}