状态模式详解
一、状态模式概述
状态模式(State Pattern)是一种行为型设计模式,它允许一个对象在其内部状态改变时改变它的行为,使对象看起来似乎修改了它的类。
核心特点
- 状态封装:将每个状态的行为封装到独立的类中
- 状态转换:对象在不同状态间透明切换
- 消除条件判断:用多态代替状态条件判断
- 开闭原则:新增状态无需修改现有代码
二、状态模式的结构
主要角色
- Context:上下文,维护当前状态
- State:抽象状态,定义状态接口
- ConcreteState:具体状态,实现特定状态行为
三、状态模式的实现
1. 基本实现
// 状态接口
public interface State {
void handle(Context context);
}
// 具体状态A
public class ConcreteStateA implements State {
public void handle(Context context) {
System.out.println("处理状态A的行为");
context.setState(new ConcreteStateB());
}
}
// 具体状态B
public class ConcreteStateB implements State {
public void handle(Context context) {
System.out.println("处理状态B的行为");
context.setState(new ConcreteStateA());
}
}
// 上下文类
public 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);
}
}
// 使用示例
Context context = new Context(new ConcreteStateA());
context.request(); // 执行状态A的行为,并切换到状态B
context.request(); // 执行状态B的行为,并切换回状态A
2. 更复杂的实现(订单状态)
// 订单状态接口
public interface OrderState {
void next(Order order);
void prev(Order order);
void printStatus();
}
// 新建状态
public class NewState implements OrderState {
public void next(Order order) {
order.setState(new PaidState());
}
public void prev(Order order) {
System.out.println("订单已在初始状态");
}
public void printStatus() {
System.out.println("订单状态:新建");
}
}
// 已支付状态
public class PaidState implements OrderState {
public void next(Order order) {
order.setState(new ShippedState());
}
public void prev(Order order) {
order.setState(new NewState());
}
public void printStatus() {
System.out.println("订单状态:已支付");
}
}
// 订单类(上下文)
public class Order {
private OrderState state;
public Order() {
this.state = new NewState();
}
public void setState(OrderState state) {
this.state = state;
}
public void nextState() {
state.next(this);
}
public void previousState() {
state.prev(this);
}
public void printStatus() {
state.printStatus();
}
}
四、状态模式的应用场景
1. 电梯状态控制
// 电梯状态接口
public interface ElevatorState {
void openDoor();
void closeDoor();
void run();
void stop();
}
// 运行状态
public class RunningState implements ElevatorState {
public void openDoor() {
System.out.println("电梯运行中不能开门");
}
public void closeDoor() {
System.out.println("电梯门已是关闭状态");
}
public void run() {
System.out.println("电梯已在运行");
}
public void stop() {
System.out.println("电梯停止运行");
}
}
// 停止状态
public class StoppedState implements ElevatorState {
public void openDoor() {
System.out.println("电梯门打开");
}
public void closeDoor() {
System.out.println("电梯门关闭");
}
public void run() {
System.out.println("电梯开始运行");
}
public void stop() {
System.out.println("电梯已是停止状态");
}
}
2. 游戏角色状态
// 游戏角色状态
public interface CharacterState {
void attack();
void defend();
void move();
}
// 正常状态
public class NormalState implements CharacterState {
public void attack() {
System.out.println("造成100%伤害");
}
public void defend() {
System.out.println("受到100%伤害");
}
public void move() {
System.out.println("移动速度100%");
}
}
// 中毒状态
public class PoisonedState implements CharacterState {
public void attack() {
System.out.println("造成80%伤害");
}
public void defend() {
System.out.println("受到120%伤害");
}
public void move() {
System.out.println("移动速度60%");
}
}
3. TCP连接状态
// TCP状态接口
public interface TCPState {
void open();
void close();
void acknowledge();
}
// 已建立连接状态
public class EstablishedState implements TCPState {
public void open() {
System.out.println("连接已建立,无需再次打开");
}
public void close() {
System.out.println("关闭TCP连接");
}
public void acknowledge() {
System.out.println("发送ACK响应");
}
}
// 监听状态
public class ListenState implements TCPState {
public void open() {
System.out.println("建立TCP连接");
}
public void close() {
System.out.println("未建立连接,无需关闭");
}
public void acknowledge() {
System.out.println("未建立连接,不能发送ACK");
}
}
五、状态模式的变体
1. 状态表驱动
public class StateMachine {
private Map<State, Map<Event, State>> transitions = new HashMap<>();
private State currentState;
public void addTransition(State source, Event event, State target) {
transitions.computeIfAbsent(source, k -> new HashMap<>())
.put(event, target);
}
public void handleEvent(Event event) {
currentState = transitions.get(currentState).get(event);
}
}
2. 状态模式与策略模式结合
public class Context {
private StateStrategy state;
public void setState(StateStrategy state) {
this.state = state;
}
public void execute() {
state.execute();
state = state.nextState();
}
}
public interface StateStrategy {
void execute();
StateStrategy nextState();
}
六、状态模式的优缺点
优点
- 单一职责:每个状态一个类
- 开闭原则:易于新增状态
- 简化上下文:消除大量条件判断
- 状态转换显式:状态转换逻辑清晰
缺点
- 类数量多:状态多时代码量大
- 过度设计:简单状态机可能不适用
- 状态共享:状态间共享数据较复杂
七、最佳实践
- 合理划分状态:避免状态粒度过细
- 共享状态对象:无状态的状态对象可共享
- 状态转换控制:集中或分散管理转换逻辑
- 结合其他模式:如与策略模式结合
- 文档化状态图:维护状态转换关系图
八、总结
状态模式是管理对象状态的有效方案,特别适用于:
- 对象行为随状态改变而改变
- 需要消除大量状态条件判断
- 状态转换逻辑复杂
- 需要清晰的状态管理
在实际开发中,状态模式常见于:
- 工作流引擎
- 游戏角色状态
- 设备控制(如电梯、自动售货机)
- 网络协议实现
- 订单生命周期管理
正确使用状态模式可以创建清晰、可维护的状态管理代码,但需要注意避免过度设计简单场景。