20.万物皆可变身术:状态模式架构全景解析

发布于:2025-08-13 ⋅ 阅读:(19) ⋅ 点赞:(0)

“我的对象就像川剧演员——在不同状态下能瞬间切换不同行为,这可比只会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 {
    @Autowired
    private 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;
    
    @PostLoad
    void initializeState() {
        this.state = StateFactory.getState(currentState);
    }
}

enum StateType { DRAFT, APPROVAL, COMPLETED }

五、最佳实践与防坑指南

使用场景

  • 对象需要根据状态改变行为
  • 需要替代复杂的条件判断
  • 状态转换逻辑明确
  • 需要清晰的状态隔离

💥 避坑要点

  1. 避免上帝状态(单个状态类过于庞大)
  2. 注意线程安全问题(状态对象的可变性)
  3. 谨慎处理状态迁移的副作用
  4. 考虑状态对象的创建成本
倒计时结束
倒计时结束
倒计时结束
Red
Green
按钮按下
30秒后
Walk
Wait
Yellow

六、扩展思考:游戏开发中的状态魔法

实现一个超级马里奥的状态系统:

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("发射火球!");
    }
}

终极挑战:如果我们要实现一个智能咖啡机的状态系统(待机、磨豆、冲泡、清洁、故障状态),你会如何设计状态之间的转换关系?欢迎在评论区留下你的设计方案!