20.万物皆可变身术:状态模式架构全景解析
目录
- 一、初阶:红绿灯的哲学课
- 二、状态模式的四种修炼境界
- 2.1 经典流派——面向对象式
- 2.2 枚举派——消灭类爆炸
- 2.3 Spring流——依赖注入的艺术
- 2.4 现代派——记录类+Lambda
- 三、实战:电商订单的七十二变
- 四、高阶技巧:状态机的N种打开方式
- 4.1 状态+策略模式
- 4.2 状态持久化
- 五、最佳实践与防坑指南
- 六、扩展思考:游戏开发中的状态魔法
“我的对象就像川剧演员——在不同状态下能瞬间切换不同行为,这可比只会if-else的呆瓜强多了!” —— 来自资深程序员的奇妙比喻
一、初阶:红绿灯的哲学课
假设我们要实现一个交通信号灯系统,新手可能会写出这样的代码:
public class TrafficLight {private String state = "RED";public void change() {if ("RED".equals(state)) {state = "GREEN";System.out.println("绿灯通行");} else if ("GREEN".equals(state)) {state = "YELLOW";System.out.println("黄灯减速");} else if ("YELLOW".equals(state)) {state = "RED";System.out.println("红灯停车");}}
}
痛点警报:当需要新增"闪烁黄灯"状态时,需要修改所有判断逻辑,这就像在已经建好的大楼里加装电梯——风险高、难度大!
二、状态模式的四种修炼境界
2.1 经典流派——面向对象式
// 状态接口
interface TrafficState {void handle(TrafficLight light);
}// 具体状态类
class RedState implements TrafficState {public void handle(TrafficLight light) {System.out.println("红灯停车");light.setState(new GreenState());}
}class GreenState implements TrafficState {public void handle(TrafficLight light) {System.out.println("绿灯通行");light.setState(new YellowState());}
}// 上下文类
class TrafficLight {private TrafficState state = new RedState();public void setState(TrafficState state) {this.state = state;}public void change() {state.handle(this);}
}// 使用示例
TrafficLight light = new TrafficLight();
light.change(); // 红灯 -> 绿灯
light.change(); // 绿灯 -> 黄灯
2.2 枚举派——消灭类爆炸
public enum ElevatorState {STOPPED {public void move(Elevator elevator) {System.out.println("电梯启动");elevator.setState(MOVING_UP);}},MOVING_UP {public void move(Elevator elevator) {System.out.println("到达顶层");elevator.setState(MOVING_DOWN);}},MOVING_DOWN {public void move(Elevator elevator) {System.out.println("到达底层");elevator.setState(STOPPED);}};public abstract void move(Elevator elevator);
}class Elevator {private ElevatorState state = ElevatorState.STOPPED;public void setState(ElevatorState state) {this.state = state;}public void call() {state.move(this);}
}
2.3 Spring流——依赖注入的艺术
public interface DocumentState {void review(Document document);
}@Component
class DraftState implements DocumentState {public void review(Document document) {if (validationPassed()) {document.setState(applicationContext.getBean(ReviewedState.class));}}
}@Service
class Document {@Autowiredprivate ApplicationContext applicationContext;private DocumentState state;public void review() {state.review(this);}
}
2.4 现代派——记录类+Lambda
public class MediaPlayer {record PlayState(Runnable onPlay) implements State {}record PauseState(Runnable onPause) implements State {}interface State {default void play(MediaPlayer player) {}default void pause(MediaPlayer player) {}}private State state = new PauseState(() -> System.out.println("播放暂停中"));public void play() {state.play(this);}void changeState(State newState) {this.state = newState;}
}
三、实战:电商订单的七十二变
public class Order {private OrderState state = new NewState();public void pay() {state.pay(this);}// 状态切换方法void setState(OrderState state) {this.state = state;}
}interface OrderState {default void pay(Order order) {throw new IllegalStateException("当前状态不支持支付");}// 其他操作方法...
}class NewState implements OrderState {public void pay(Order order) {System.out.println("支付成功");order.setState(new PaidState());}
}class PaidState implements OrderState {public void ship(Order order) {System.out.println("开始发货");order.setState(new ShippedState());}
}
四、高阶技巧:状态机的N种打开方式
4.1 状态+策略模式
public class GameCharacter {private State state = new NormalState();public void attack() {state.attack().execute();}
}interface State {Command attack();Command defend();
}class BerserkState implements State {public Command attack() {return () -> System.out.println("狂暴攻击!伤害+50%");}
}
4.2 状态持久化
public class Workflow {@Enumerated(EnumType.STRING)private StateType currentState;@Transient // 不持久化private State state;@PostLoadvoid initializeState() {this.state = StateFactory.getState(currentState);}
}enum StateType { DRAFT, APPROVAL, COMPLETED }
五、最佳实践与防坑指南
✅ 使用场景:
- 对象需要根据状态改变行为
- 需要替代复杂的条件判断
- 状态转换逻辑明确
- 需要清晰的状态隔离
💥 避坑要点:
- 避免上帝状态(单个状态类过于庞大)
- 注意线程安全问题(状态对象的可变性)
- 谨慎处理状态迁移的副作用
- 考虑状态对象的创建成本
六、扩展思考:游戏开发中的状态魔法
实现一个超级马里奥的状态系统:
public class Mario {private MarioState state = new SmallState();public void takeMushroom() {state = state.takeMushroom();}public void takeFireFlower() {state = state.takeFireFlower();}
}interface MarioState {MarioState takeMushroom();MarioState takeFireFlower();default void attack() {System.out.println("跳跃攻击");}
}class FireMario implements MarioState {public MarioState takeMushroom() {return this; // 形态不变}public void attack() {System.out.println("发射火球!");}
}
终极挑战:如果我们要实现一个智能咖啡机的状态系统(待机、磨豆、冲泡、清洁、故障状态),你会如何设计状态之间的转换关系?欢迎在评论区留下你的设计方案!