设计模式:状态模式详解-让对象的行为随状态改变而改变
-
- [1. 什么是状态模式?](#1. 什么是状态模式?)
- [2. 从一个实际问题开始](#2. 从一个实际问题开始)
- [3. 状态模式的结构](#3. 状态模式的结构)
- [4. 状态模式的Java实现](#4. 状态模式的Java实现)
- [5. 状态模式的优势](#5. 状态模式的优势)
-
- [5.1 对比原始实现](#5.1 对比原始实现)
- [5.2 核心优势](#5.2 核心优势)
- [6. 状态模式的实际应用场景](#6. 状态模式的实际应用场景)
- [7. 状态模式的变体](#7. 状态模式的变体)
-
- [7.1 共享状态对象](#7.1 共享状态对象)
- [7.2 状态转换表](#7.2 状态转换表)
- [7.3 状态模式与策略模式的比较](#7.3 状态模式与策略模式的比较)
- [8. Spring框架中的状态模式](#8. Spring框架中的状态模式)
-
- [8.1 Spring状态机(State Machine)](#8.1 Spring状态机(State Machine))
- [8.2 线程状态管理](#8.2 线程状态管理)
- [9. 状态模式的最佳实践](#9. 状态模式的最佳实践)
-
- [9.1 何时使用状态模式](#9.1 何时使用状态模式)
- [9.2 实现建议](#9.2 实现建议)
- [9.3 状态对象的创建](#9.3 状态对象的创建)
- [10. 状态模式的局限性](#10. 状态模式的局限性)
- [11. 总结](#11. 总结)
在软件开发中,我们经常会遇到这样的对象:它的行为取决于自身的状态,并且需要在不同状态下表现出不同的行为。如果使用大量的 if-else或 switch-case语句来判断状态,代码会变得难以维护和扩展。状态模式提供了一种优雅的解决方案。
1. 什么是状态模式?
状态模式是一种行为设计模式,它允许一个对象在其内部状态改变时改变它的行为,对象看起来好像修改了它的类。
简单来说,状态模式的核心思想是:
- 将状态抽象化:将每个状态封装成独立的类
- 将行为状态化:将与状态相关的行为分散到各个状态类中
- 消除条件判断:用多态代替大量的条件判断语句
2. 从一个实际问题开始
假设我们要实现一个电梯系统,电梯有四种状态:开门、关门、运行、停止。电梯在不同状态下的行为不同:
- 开门状态:不能开门(已经在开门),可以关门
- 关门状态:可以开门,可以运行
- 运行状态:不能开门,不能关门,可以停止
- 停止状态:可以开门
如果不使用设计模式,我们可能会写出这样的代码:
java
// 反面教材:使用大量的if-else判断
public class Elevator {
private static final int OPEN = 1;
private static final int CLOSE = 2;
private static final int RUN = 3;
private static final int STOP = 4;
private int state;
public Elevator() {
this.state = STOP; // 初始状态为停止
}
public void open() {
if (state == OPEN) {
System.out.println("电梯门已经是打开状态");
} else if (state == CLOSE) {
System.out.println("电梯门打开");
state = OPEN;
} else if (state == RUN) {
System.out.println("运行状态不能开门");
} else if (state == STOP) {
System.out.println("电梯门打开");
state = OPEN;
}
}
public void close() {
if (state == OPEN) {
System.out.println("电梯门关闭");
state = CLOSE;
} else if (state == CLOSE) {
System.out.println("电梯门已经是关闭状态");
} else if (state == RUN) {
System.out.println("运行状态不能关门");
} else if (state == STOP) {
System.out.println("电梯已经是停止状态");
}
}
public void run() {
if (state == OPEN) {
System.out.println("开门状态不能运行");
} else if (state == CLOSE) {
System.out.println("电梯开始运行");
state = RUN;
} else if (state == RUN) {
System.out.println("电梯已经在运行");
} else if (state == STOP) {
System.out.println("电梯开始运行");
state = RUN;
}
}
public void stop() {
if (state == OPEN) {
System.out.println("开门状态不能停止");
} else if (state == CLOSE) {
System.out.println("电梯停止");
state = STOP;
} else if (state == RUN) {
System.out.println("电梯停止");
state = STOP;
} else if (state == STOP) {
System.out.println("电梯已经是停止状态");
}
}
}
这段代码的问题:
- 违反开闭原则:新增状态需要修改所有方法
- 代码臃肿:每个方法都有复杂的条件判断
- 难以维护:状态转换逻辑分散在各个方法中
- 职责不清晰:一个类负责所有状态的行为
3. 状态模式的结构
状态模式包含三个核心角色:
拥有
实现
实现
使用
使用
Context
-state: State
+request() : void
+setState(state: State) : void
<<interface>>
State
+handle(context: Context) : void
ConcreteStateA
+handle(context: Context) : void
ConcreteStateB
+handle(context: Context) : void
- 上下文:维护一个具体状态对象的实例,定义客户感兴趣的接口
- 抽象状态:定义一个接口,用以封装与上下文的一个特定状态相关的行为
- 具体状态:实现抽象状态接口,定义该状态下的行为
4. 状态模式的Java实现
让我们用状态模式重构电梯系统:
步骤1:定义状态接口
java
/**
* 电梯状态接口
* 定义电梯在不同状态下的行为
*/
public interface ElevatorState {
/**
* 开门
*/
void open();
/**
* 关门
*/
void close();
/**
* 运行
*/
void run();
/**
* 停止
*/
void stop();
}
步骤2:实现具体状态类
java
/**
* 开门状态
*/
public class OpenState implements ElevatorState {
private Elevator elevator;
public OpenState(Elevator elevator) {
this.elevator = elevator;
}
@Override
public void open() {
System.out.println("电梯门已经是打开状态");
}
@Override
public void close() {
System.out.println("电梯门关闭");
elevator.setState(elevator.getCloseState());
}
@Override
public void run() {
System.out.println("开门状态不能运行");
}
@Override
public void stop() {
System.out.println("开门状态不能停止");
}
}
/**
* 关门状态
*/
public class CloseState implements ElevatorState {
private Elevator elevator;
public CloseState(Elevator elevator) {
this.elevator = elevator;
}
@Override
public void open() {
System.out.println("电梯门打开");
elevator.setState(elevator.getOpenState());
}
@Override
public void close() {
System.out.println("电梯门已经是关闭状态");
}
@Override
public void run() {
System.out.println("电梯开始运行");
elevator.setState(elevator.getRunState());
}
@Override
public void stop() {
System.out.println("电梯停止");
elevator.setState(elevator.getStopState());
}
}
/**
* 运行状态
*/
public class RunState implements ElevatorState {
private Elevator elevator;
public RunState(Elevator elevator) {
this.elevator = elevator;
}
@Override
public void open() {
System.out.println("运行状态不能开门");
}
@Override
public void close() {
System.out.println("运行状态不能关门");
}
@Override
public void run() {
System.out.println("电梯已经在运行");
}
@Override
public void stop() {
System.out.println("电梯停止");
elevator.setState(elevator.getStopState());
}
}
/**
* 停止状态
*/
public class StopState implements ElevatorState {
private Elevator elevator;
public StopState(Elevator elevator) {
this.elevator = elevator;
}
@Override
public void open() {
System.out.println("电梯门打开");
elevator.setState(elevator.getOpenState());
}
@Override
public void close() {
System.out.println("电梯已经是停止状态");
}
@Override
public void run() {
System.out.println("电梯开始运行");
elevator.setState(elevator.getRunState());
}
@Override
public void stop() {
System.out.println("电梯已经是停止状态");
}
}
步骤3:创建上下文类
java
/**
* 电梯上下文类
* 维护当前状态,并将请求委托给当前状态对象
*/
public class Elevator {
// 定义所有状态
private ElevatorState openState;
private ElevatorState closeState;
private ElevatorState runState;
private ElevatorState stopState;
// 当前状态
private ElevatorState currentState;
public Elevator() {
// 初始化所有状态
openState = new OpenState(this);
closeState = new CloseState(this);
runState = new RunState(this);
stopState = new StopState(this);
// 设置初始状态
currentState = stopState;
}
// 状态操作方法 - 委托给当前状态
public void open() {
currentState.open();
}
public void close() {
currentState.close();
}
public void run() {
currentState.run();
}
public void stop() {
currentState.stop();
}
// 状态设置方法
public void setState(ElevatorState state) {
this.currentState = state;
}
// 获取各个状态的方法
public ElevatorState getOpenState() {
return openState;
}
public ElevatorState getCloseState() {
return closeState;
}
public ElevatorState getRunState() {
return runState;
}
public ElevatorState getStopState() {
return stopState;
}
// 获取当前状态
public String getCurrentStateName() {
if (currentState == openState) {
return "开门状态";
} else if (currentState == closeState) {
return "关门状态";
} else if (currentState == runState) {
return "运行状态";
} else {
return "停止状态";
}
}
}
步骤4:客户端使用
java
public class Client {
public static void main(String[] args) {
System.out.println("=== 电梯状态演示 ===\n");
// 创建电梯
Elevator elevator = new Elevator();
System.out.println("当前状态:" + elevator.getCurrentStateName());
// 测试状态转换
System.out.println("\n1. 尝试开门");
elevator.open();
System.out.println("当前状态:" + elevator.getCurrentStateName());
System.out.println("\n2. 尝试关门");
elevator.close();
System.out.println("当前状态:" + elevator.getCurrentStateName());
System.out.println("\n3. 尝试运行");
elevator.run();
System.out.println("当前状态:" + elevator.getCurrentStateName());
System.out.println("\n4. 运行中尝试开门");
elevator.open();
System.out.println("当前状态:" + elevator.getCurrentStateName());
System.out.println("\n5. 停止电梯");
elevator.stop();
System.out.println("当前状态:" + elevator.getCurrentStateName());
System.out.println("\n6. 尝试在停止状态关门");
elevator.close();
System.out.println("当前状态:" + elevator.getCurrentStateName());
// 演示完整流程
System.out.println("\n=== 完整使用流程 ===");
elevator = new Elevator();
System.out.println("初始状态:" + elevator.getCurrentStateName());
System.out.println("\n乘客进入电梯:");
elevator.open();
System.out.println("状态:" + elevator.getCurrentStateName());
System.out.println("\n电梯关门:");
elevator.close();
System.out.println("状态:" + elevator.getCurrentStateName());
System.out.println("\n电梯运行:");
elevator.run();
System.out.println("状态:" + elevator.getCurrentStateName());
System.out.println("\n到达目标楼层:");
elevator.stop();
System.out.println("状态:" + elevator.getCurrentStateName());
System.out.println("\n乘客离开电梯:");
elevator.open();
System.out.println("状态:" + elevator.getCurrentStateName());
System.out.println("\n电梯关门待机:");
elevator.close();
System.out.println("状态:" + elevator.getCurrentStateName());
}
}
输出结果:
=== 电梯状态演示 ===
当前状态:停止状态
1. 尝试开门
电梯门打开
当前状态:开门状态
2. 尝试关门
电梯门关闭
当前状态:关门状态
3. 尝试运行
电梯开始运行
当前状态:运行状态
4. 运行中尝试开门
运行状态不能开门
当前状态:运行状态
5. 停止电梯
电梯停止
当前状态:停止状态
6. 尝试在停止状态关门
电梯已经是停止状态
当前状态:停止状态
=== 完整使用流程 ===
初始状态:停止状态
乘客进入电梯:
电梯门打开
状态:开门状态
电梯关门:
电梯门关闭
状态:关门状态
电梯运行:
电梯开始运行
状态:运行状态
到达目标楼层:
电梯停止
状态:停止状态
乘客离开电梯:
电梯门打开
状态:开门状态
电梯关门待机:
电梯门关闭
状态:关门状态
5. 状态模式的优势
5.1 对比原始实现
| 对比维度 | 原始实现(if-else) | 状态模式 |
|---|---|---|
| 新增状态 | 需要修改所有方法 | 只需新增一个状态类 |
| 状态转换逻辑 | 分散在各个方法中 | 集中在状态类中 |
| 代码结构 | 一个方法包含所有逻辑 | 逻辑分散到各个状态类 |
| 可测试性 | 难以单独测试每种状态 | 每个状态类可独立测试 |
| 遵循原则 | 违反开闭原则、单一职责 | 符合开闭原则、单一职责 |
5.2 核心优势
- 消除条件判断:用多态代替复杂的条件判断语句
- 符合单一职责原则:每个状态类只负责自己的行为
- 符合开闭原则:新增状态无需修改现有代码
- 提高可维护性:状态转换逻辑局部化,易于理解和修改
- 状态转换明确:状态转换逻辑集中在状态类中,清晰可见
6. 状态模式的实际应用场景
场景1:订单状态管理
java
/**
* 订单状态接口
*/
public interface OrderState {
/**
* 支付
*/
void pay(OrderContext context);
/**
* 发货
*/
void ship(OrderContext context);
/**
* 确认收货
*/
void receive(OrderContext context);
/**
* 取消订单
*/
void cancel(OrderContext context);
/**
* 申请退款
*/
void refund(OrderContext context);
}
/**
* 订单上下文
*/
public class OrderContext {
private OrderState currentState;
private String orderId;
// 各个状态实例
private OrderState pendingState;
private OrderState paidState;
private OrderState shippedState;
private OrderState receivedState;
private OrderState cancelledState;
private OrderState refundedState;
public OrderContext(String orderId) {
this.orderId = orderId;
// 初始化所有状态
pendingState = new PendingState(this);
paidState = new PaidState(this);
shippedState = new ShippedState(this);
receivedState = new ReceivedState(this);
cancelledState = new CancelledState(this);
refundedState = new RefundedState(this);
// 初始状态:待支付
currentState = pendingState;
}
// 委托方法
public void pay() {
currentState.pay(this);
}
public void ship() {
currentState.ship(this);
}
public void receive() {
currentState.receive(this);
}
public void cancel() {
currentState.cancel(this);
}
public void refund() {
currentState.refund(this);
}
// 设置状态
public void setState(OrderState state) {
this.currentState = state;
System.out.println("订单状态变更为:" + state.getClass().getSimpleName());
}
// Getter方法
public OrderState getPendingState() { return pendingState; }
public OrderState getPaidState() { return paidState; }
public OrderState getShippedState() { return shippedState; }
public OrderState getReceivedState() { return receivedState; }
public OrderState getCancelledState() { return cancelledState; }
public OrderState getRefundedState() { return refundedState; }
public String getOrderId() { return orderId; }
}
/**
* 待支付状态
*/
public class PendingState implements OrderState {
private OrderContext context;
public PendingState(OrderContext context) {
this.context = context;
}
@Override
public void pay(OrderContext context) {
System.out.println("订单支付成功");
context.setState(context.getPaidState());
}
@Override
public void ship(OrderContext context) {
System.out.println("订单未支付,不能发货");
}
@Override
public void receive(OrderContext context) {
System.out.println("订单未支付,不能确认收货");
}
@Override
public void cancel(OrderContext context) {
System.out.println("订单已取消");
context.setState(context.getCancelledState());
}
@Override
public void refund(OrderContext context) {
System.out.println("订单未支付,不能退款");
}
}
/**
* 已支付状态
*/
public class PaidState implements OrderState {
@Override
public void pay(OrderContext context) {
System.out.println("订单已支付,无需重复支付");
}
@Override
public void ship(OrderContext context) {
System.out.println("订单发货成功");
context.setState(context.getShippedState());
}
@Override
public void receive(OrderContext context) {
System.out.println("订单尚未发货,不能确认收货");
}
@Override
public void cancel(OrderContext context) {
System.out.println("订单已取消,发起退款");
context.setState(context.getRefundedState());
}
@Override
public void refund(OrderContext context) {
System.out.println("订单退款成功");
context.setState(context.getRefundedState());
}
}
场景2:TCP连接状态
java
/**
* TCP连接状态
*/
public interface TCPState {
void open(TCPConnection connection);
void close(TCPConnection connection);
void acknowledge(TCPConnection connection);
}
/**
* TCP连接
*/
public class TCPConnection {
private TCPState state;
// 各个状态
private TCPState closedState;
private TCPState listenState;
private TCPState establishedState;
public TCPConnection() {
closedState = new TCPClosedState();
listenState = new TCPListenState();
establishedState = new TCPEstablishedState();
state = closedState; // 初始状态:关闭
}
public void setState(TCPState state) {
this.state = state;
}
public void open() {
state.open(this);
}
public void close() {
state.close(this);
}
public void acknowledge() {
state.acknowledge(this);
}
// Getter方法
public TCPState getClosedState() { return closedState; }
public TCPState getListenState() { return listenState; }
public TCPState getEstablishedState() { return establishedState; }
}
/**
* TCP关闭状态
*/
public class TCPClosedState implements TCPState {
@Override
public void open(TCPConnection connection) {
System.out.println("打开连接");
connection.setState(connection.getListenState());
}
@Override
public void close(TCPConnection connection) {
System.out.println("连接已经是关闭状态");
}
@Override
public void acknowledge(TCPConnection connection) {
System.out.println("连接关闭,无法确认");
}
}
/**
* TCP监听状态
*/
public class TCPListenState implements TCPState {
@Override
public void open(TCPConnection connection) {
System.out.println("连接已经是打开状态");
}
@Override
public void close(TCPConnection connection) {
System.out.println("关闭连接");
connection.setState(connection.getClosedState());
}
@Override
public void acknowledge(TCPConnection connection) {
System.out.println("确认连接");
connection.setState(connection.getEstablishedState());
}
}
7. 状态模式的变体
7.1 共享状态对象
在某些情况下,多个上下文可以共享同一个状态对象。这时状态对象不应该持有上下文的引用。
java
/**
* 可共享的状态对象
*/
public class SharedState implements State {
// 不持有上下文引用
@Override
public void handle() {
System.out.println("处理共享状态");
// 不能直接操作上下文,需要其他方式传递上下文信息
}
}
/**
* 上下文类
*/
public class SharedContext {
private State state;
public void request() {
state.handle();
// 根据处理结果决定状态转换
if (shouldChangeState()) {
state = nextState();
}
}
private boolean shouldChangeState() {
// 判断是否需要转换状态
return true;
}
private State nextState() {
// 返回下一个状态
return new AnotherState();
}
}
7.2 状态转换表
对于复杂的状态转换,可以使用状态转换表来管理。
java
/**
* 使用状态转换表
*/
public class StateMachine {
// 状态转换表:Map<当前状态, Map<事件, 下一状态>>
private Map<State, Map<Event, State>> transitionTable = new HashMap<>();
private State currentState;
public StateMachine(State initialState) {
this.currentState = initialState;
initTransitionTable();
}
private void initTransitionTable() {
// 初始化状态转换表
Map<Event, State> fromStateA = new HashMap<>();
fromStateA.put(Event.EVENT_1, State.STATE_B);
fromStateA.put(Event.EVENT_2, State.STATE_C);
transitionTable.put(State.STATE_A, fromStateA);
Map<Event, State> fromStateB = new HashMap<>();
fromStateB.put(Event.EVENT_3, State.STATE_C);
transitionTable.put(State.STATE_B, fromStateB);
// 更多状态转换...
}
public void handleEvent(Event event) {
Map<Event, State> transitions = transitionTable.get(currentState);
if (transitions != null && transitions.containsKey(event)) {
State nextState = transitions.get(event);
System.out.println("状态转换:" + currentState + " -> " + nextState);
currentState = nextState;
} else {
System.out.println("无效的事件:" + event + ",当前状态:" + currentState);
}
}
}
enum State {
STATE_A, STATE_B, STATE_C
}
enum Event {
EVENT_1, EVENT_2, EVENT_3
}
7.3 状态模式与策略模式的比较
状态模式和策略模式在结构上很相似,但它们的意图不同:
| 对比维度 | 状态模式 | 策略模式 |
|---|---|---|
| 意图 | 对象的行为随状态改变 | 封装可互换的算法 |
| 状态转换 | 状态对象知道下一个状态 | 客户端选择策略 |
| 状态数量 | 通常状态数量有限 | 策略数量可能很多 |
| 状态知晓 | 状态知道上下文 | 策略通常不知道上下文 |
| 示例 | 订单状态、电梯状态 | 排序算法、支付方式 |
8. Spring框架中的状态模式
Spring框架虽然没有直接使用经典的状态模式,但其状态管理思想无处不在:
8.1 Spring状态机(State Machine)
java
// Spring Statemachine 示例
@Configuration
@EnableStateMachine
public class OrderStateMachineConfig extends StateMachineConfigurerAdapter<String, String> {
@Override
public void configure(StateMachineStateConfigurer<String, String> states) throws Exception {
states
.withStates()
.initial("CREATED") // 初始状态
.state("PAID") // 已支付
.state("SHIPPED") // 已发货
.state("DELIVERED") // 已送达
.state("CANCELLED"); // 已取消
}
@Override
public void configure(StateMachineTransitionConfigurer<String, String> transitions) throws Exception {
transitions
.withExternal()
.source("CREATED").target("PAID").event("PAY")
.and()
.withExternal()
.source("PAID").target("SHIPPED").event("SHIP")
.and()
.withExternal()
.source("SHIPPED").target("DELIVERED").event("DELIVER")
.and()
.withExternal()
.source("CREATED").target("CANCELLED").event("CANCEL")
.and()
.withExternal()
.source("PAID").target("CANCELLED").event("CANCEL");
}
}
// 使用状态机
@Service
public class OrderService {
@Autowired
private StateMachine<String, String> stateMachine;
public void payOrder(String orderId) {
// 发送支付事件
stateMachine.sendEvent("PAY");
// 获取当前状态
String currentState = stateMachine.getState().getId();
System.out.println("订单状态:" + currentState);
}
}
8.2 线程状态管理
java
/**
* 模拟线程状态管理
*/
public class ThreadStateManager {
public enum ThreadState {
NEW, // 新建
RUNNABLE, // 可运行
RUNNING, // 运行中
BLOCKED, // 阻塞
WAITING, // 等待
TERMINATED // 终止
}
private ThreadState currentState = ThreadState.NEW;
public synchronized void start() {
if (currentState == ThreadState.NEW) {
currentState = ThreadState.RUNNABLE;
System.out.println("线程进入可运行状态");
} else {
throw new IllegalThreadStateException("线程不能从" + currentState + "状态开始");
}
}
public synchronized void run() {
if (currentState == ThreadState.RUNNABLE) {
currentState = ThreadState.RUNNING;
System.out.println("线程开始运行");
} else {
throw new IllegalThreadStateException("线程不能从" + currentState + "状态运行");
}
}
public synchronized void block() {
if (currentState == ThreadState.RUNNING) {
currentState = ThreadState.BLOCKED;
System.out.println("线程被阻塞");
}
}
public synchronized void terminate() {
if (currentState != ThreadState.TERMINATED) {
currentState = ThreadState.TERMINATED;
System.out.println("线程终止");
}
}
public ThreadState getCurrentState() {
return currentState;
}
}
9. 状态模式的最佳实践
9.1 何时使用状态模式
| 场景 | 是否适合状态模式 | 说明 |
|---|---|---|
| 对象的行为取决于状态 | ✅ 非常适合 | 如订单、电梯、线程等 |
| 有大量的状态判断 | ✅ 非常适合 | 用多态代替if-else |
| 状态转换复杂 | ✅ 非常适合 | 状态转换逻辑局部化 |
| 状态数量很少 | ❌ 可能过度设计 | 简单的if-else更直接 |
| 状态不频繁变化 | ❌ 可能过度设计 | 考虑其他模式 |
9.2 实现建议
- 将状态定义为不可变对象:状态对象通常是无状态的,可以被多个上下文共享
- 使用枚举简化状态管理:对于有限的状态,可以使用枚举
- 考虑使用状态机框架:对于复杂的状态转换,考虑使用Spring Statemachine等框架
- 分离状态转换逻辑:将状态转换逻辑集中在状态类中
- 提供状态查询接口:允许客户端查询当前状态
9.3 状态对象的创建
java
/**
* 状态工厂 - 管理状态对象的创建
*/
public class StateFactory {
// 使用单例模式共享状态对象
private static final Map<String, State> states = new HashMap<>();
static {
// 初始化所有状态对象
states.put("OPEN", new OpenState());
states.put("CLOSE", new CloseState());
states.put("RUN", new RunState());
states.put("STOP", new StopState());
}
public static State getState(String stateName) {
State state = states.get(stateName);
if (state == null) {
throw new IllegalArgumentException("未知状态: " + stateName);
}
return state;
}
// 延迟初始化
public static State getStateLazy(String stateName) {
return states.computeIfAbsent(stateName, name -> {
switch (name) {
case "OPEN": return new OpenState();
case "CLOSE": return new CloseState();
case "RUN": return new RunState();
case "STOP": return new StopState();
default: throw new IllegalArgumentException("未知状态: " + name);
}
});
}
}
10. 状态模式的局限性
- 可能增加类的数量:每个状态一个类,可能导致类数量增加
- 状态转换逻辑分散:状态转换逻辑分散在各个状态类中
- 共享状态需要特殊处理:如果状态对象需要持有上下文引用,则不能共享
- 可能过度设计:对于简单的状态转换,使用if-else更直接
11. 总结
状态模式是一种强大的设计模式,它将对象的状态封装成独立的类,使得对象的行为能够随着内部状态的改变而改变。通过使用状态模式,我们可以:
- 消除条件判断:用多态代替复杂的if-else语句
- 提高代码可维护性:每个状态类职责单一,易于理解和修改
- 符合开闭原则:新增状态无需修改现有代码
- 状态转换清晰:状态转换逻辑集中在状态类中
状态模式的核心价值在于它将与特定状态相关的行为局部化,并且将不同状态的行为分割开来。这使得增加新的状态变得容易,并且减少了状态转换的条件逻辑。
使用状态模式的关键点:
- 确定对象有哪些状态
- 确定每个状态下的行为
- 确定状态之间的转换条件
- 将每个状态封装成独立的类
状态模式在游戏开发、工作流引擎、订单系统等领域有着广泛的应用。