状态模式(State Pattern)详解
状态模式是一种行为设计模式,它允许对象在其内部状态改变时改变它的行为,使对象看起来似乎修改了它的类。
核心概念
- 上下文(Context):维护一个具体状态对象的实例,定义客户端接口
- 抽象状态(State):定义一个接口,用于封装与上下文特定状态相关的行为
- 具体状态(Concrete State):实现抽象状态接口,每个子类实现一个与上下文状态相关的行为
模式结构
Context
|__ state: State
|__ request()
|__ changeState(state: State)
State (Interface/Abstract Class)
|__ handle()
ConcreteStateA
|__ handle()
ConcreteStateB
|__ handle()
实现示例(java)
// State接口
interface State {
void handle(Context context);
}
// 具体状态A
class ConcreteStateA implements State {
@Override
public void handle(Context context) {
System.out.println("当前状态是 A.");
context.setState(new ConcreteStateB());
}
}
// 具体状态B
class ConcreteStateB implements State {
@Override
public void handle(Context context) {
System.out.println("当前状态是 B.");
context.setState(new ConcreteStateA());
}
}
// Context类
class Context {
private State state;
public Context(State state) {
this.state = state;
}
public void setState(State state) {
this.state = state;
}
public void request() {
state.handle(this);
}
}
// 客户端代码
public class StatePatternDemo {
public static void main(String[] args) {
Context context = new Context(new ConcreteStateA());
// 不断请求,观察状态变化
context.request();
context.request();
context.request();
context.request();
}
}
实现示例(C++)
#include <iostream>
using namespace std;
// 前向声明
class Context;
// State接口
class State {
public:
virtual void handle(Context* context) = 0;
virtual ~State() = default;
};
// Context类
class Context {
private:
State* state;
public:
Context(State* state) : state(state) {}
void setState(State* newState) {
delete state; // 释放旧状态
state = newState;
}
void request() {
state->handle(this);
}
~Context() {
delete state;
}
};
// 前向声明 ConcreteStateB
class ConcreteStateB;
// 具体状态A
class ConcreteStateA : public State {
public:
void handle(Context* context) override;
};
// 具体状态B
class ConcreteStateB : public State {
public:
void handle(Context* context) override {
cout << "当前状态是 B." << endl;
context->setState(new ConcreteStateA());
}
};
// 实现 ConcreteStateA 的 handle 方法(需要在 ConcreteStateB 定义之后)
void ConcreteStateA::handle(Context* context) {
cout << "当前状态是 A." << endl;
context->setState(new ConcreteStateB());
}
// 客户端代码
int main() {
Context context(new ConcreteStateA());
// 不断请求,观察状态变化
context.request();
context.request();
context.request();
context.request();
return 0;
}
}
状态模式 vs 策略模式
虽然两者结构相似,但目的不同:
特性 | 状态模式 | 策略模式 |
---|---|---|
目的 | 处理对象内部状态变化 | 封装可互换的算法 |
状态转换 | 状态可以自动转换 | 策略通常由客户端选择 |
知晓性 | 状态知道其他状态 | 策略相互独立 |
典型应用 | 有限状态机、工作流 | 算法选择、支付方式 |
状态模式优点
- 单一职责原则:将与特定状态相关的代码组织在独立类中
- 开闭原则:无需修改已有状态类和上下文即可引入新状态
- 消除条件语句:避免上下文中的大型状态条件判断
- 状态转换显式化:状态转换更加明确和可控
适用场景
- 对象行为取决于它的状态,且必须在运行时根据状态改变行为
- 操作中包含大量条件语句,且这些条件取决于对象状态
- 需要实现状态转换逻辑时
- 需要组织特定于状态的代码时
现实生活例子:电梯控制系统
电梯可以有多种状态:
- 开门状态(OpenState)
- 关门状态(CloseState)
- 运行状态(RunState)
- 停止状态(StopState)
每种状态下电梯对相同请求(如按楼层按钮)的响应不同:
class Elevator {
// 上下文类
// 持有当前状态
// 提供请求方法
};
class ElevatorState {
// 抽象状态
virtual void openDoor() = 0;
virtual void closeDoor() = 0;
virtual void run() = 0;
virtual void stop() = 0;
};
class OpenState : public ElevatorState {
// 开门状态下的行为
void closeDoor() override {
// 可以关门,切换到关门状态
}
// 其他方法实现...
};
状态模式使得电梯在不同状态下对相同请求做出不同响应,且状态转换逻辑清晰。