状态模式
状态模式(State Pattern)是一种行为型设计模式,允许对象在内部状态发生变化时改变其行为,看起来像是改变了对象本身的类。它通过将状态相关的行为封装到单独的状态类中,使得对象的行为能够根据状态动态切换,常用于需要根据状态执行不同逻辑的场景。
状态模式的组成
状态模式通常包含以下几个角色:
- 上下文(Context):持有当前状态的对象,提供接口供外部调用,并将具体行为委托给当前状态对象。
- 状态接口(State):定义状态相关的行为接口,所有具体状态类都实现该接口。
- 具体状态(Concrete State):实现状态接口,定义特定状态下的行为,并可能触发状态转换。
工作原理
- 上下文对象持有一个状态对象,表示当前状态。
- 当外部调用上下文的方法时,上下文将请求委托给当前状态对象处理。
- 状态对象执行特定行为,并可能根据条件触发上下文切换到其他状态。
UML 类图
┌────────────────┐ ┌────────────────┐
│ Context │ │ State │
├────────────────┤ ├────────────────┤
│ state │<----->│ handle() │
│ setState() │ └────────────────┘
│ request() │
└────────────────┘
↑
┌────────────────┐ ┌────────────────┐
│ ConcreteStateA │ │ ConcreteStateB │
├────────────────┤ ├────────────────┤
│ handle() │ │ handle() │
└────────────────┘ └────────────────┘
代码示例(以 Java 为例)
以下是一个状态模式的实现,模拟一个电灯开关的场景,电灯有“开”和“关”两种状态:
// 状态接口
interface State {
void handle(Context context);
}
// 具体状态:开
class OnState implements State {
@Override
public void handle(Context context) {
System.out.println("电灯已打开");
// 切换到关状态
context.setState(new OffState());
}
}
// 具体状态:关
class OffState implements State {
@Override
public void handle(Context context) {
System.out.println("电灯已关闭");
// 切换到开状态
context.setState(new OnState());
}
}
// 上下文:电灯
class Context {
private State state;
public Context() {
// 初始状态为关闭
state = new OffState();
}
public void setState(State state) {
this.state = state;
}
public void request() {
state.handle(this);
}
}
// 测试代码
public class Main {
public static void main(String[] args) {
Context lamp = new Context();
// 模拟开关操作
lamp.request(); // 关闭 -> 打开
lamp.request(); // 打开 -> 关闭
lamp.request(); // 关闭 -> 打开
}
}
输出:
电灯已关闭
电灯已打开
电灯已关闭
状态模式的特点
- 优点:
- 将状态相关的行为封装到独立的状态类中,符合单一职责原则。
- 状态转换逻辑清晰,易于维护和扩展。
- 避免了大量的条件语句(如
if-else
或switch
),使代码更简洁。 - 缺点:
- 如果状态数量较多,会导致状态类数量增加,系统复杂度可能上升。
- 状态切换逻辑可能分散在多个状态类中,需小心管理。
使用场景
- 当对象的行为依赖于其状态,且状态变化频繁时:
- 订单状态管理(如待支付、已支付、已发货、已完成)。
- 游戏角色状态(如正常、眩晕、中毒)。
- UI 控件状态(如启用、禁用、选中)。
- 需要替代大量条件语句来处理不同状态的场景。
注意事项
- 状态转换:状态转换可以由上下文控制,也可以在具体状态类中实现,具体取决于业务需求。
- 状态共享:如果状态对象无内部数据,可以使用单例模式或静态实例以减少内存开销。
- 与策略模式的区别:
- 状态模式侧重于根据状态切换行为,状态间可能存在转换关系。
- 策略模式侧重于行为的选择,策略间通常独立且无状态转换。
- 扩展性:新增状态时,只需添加新的具体状态类并实现状态接口,符合开闭原则。
总结
状态模式通过将状态和行为封装到独立的状态类中,实现了对象行为随状态动态变化的效果。它适用于状态驱动的场景,能有效减少条件语句,提高代码的可维护性和扩展性。在实际应用中,状态模式常用于流程管理、游戏开发和 UI 状态控制等领域。