Skip to content

状态模式 常用

状态模式(State Pattern)允许对象在内部状态改变时改变它的行为,对象看起来似乎修改了它的类。它将状态相关的行为封装到独立的状态类中,避免大量条件判断。

优缺点

优点缺点
将与特定状态相关的行为局部化,并划分到不同状态类状态类增多,如果状态少或变化少则过度设计
消除庞大的条件分支(if-else / switch)状态流转逻辑分散在状态类中,不易全局把控
状态转换显式化,提高代码可读性和可维护性每个状态类都需了解其前后驱状态,产生类间依赖
符合开闭原则,新增状态无需修改现有状态类

适用场景

  • 对象的行为依赖于其状态,且状态改变时行为需随之改变
  • 操作中包含大量与状态相关的条件分支语句
  • 状态转换规则复杂,且需要显式管理

状态模式 vs 策略模式

模式意图状态知识
状态模式状态改变 → 行为改变,状态间可自动切换状态知道其他状态的存在
策略模式行为可替换,客户端指定策略策略之间彼此独立,互不知晓

状态模式

java
// 状态接口
interface State {
    void insertCoin();
    void pressButton();
    void dispense();
}

// 具体状态:无硬币
class NoCoinState implements State {
    private VendingMachine machine;

    public NoCoinState(VendingMachine machine) {
        this.machine = machine;
    }

    @Override
    public void insertCoin() {
        System.out.println("投币成功");
        machine.setState(machine.getHasCoinState());  // 切换到「有硬币」状态
    }

    @Override
    public void pressButton() {
        System.out.println("请先投币");
    }

    @Override
    public void dispense() {
        System.out.println("请先投币");
    }
}

// 具体状态:有硬币
class HasCoinState implements State {
    private VendingMachine machine;

    public HasCoinState(VendingMachine machine) {
        this.machine = machine;
    }

    @Override
    public void insertCoin() {
        System.out.println("已投币,无需重复投币");
    }

    @Override
    public void pressButton() {
        System.out.println("按钮已按下,准备出货");
        machine.setState(machine.getSoldState());  // 切换到「售出中」状态
    }

    @Override
    public void dispense() {
        System.out.println("请先按按钮");
    }
}

// 具体状态:售出中
class SoldState implements State {
    private VendingMachine machine;

    public SoldState(VendingMachine machine) {
        this.machine = machine;
    }

    @Override
    public void insertCoin() {
        System.out.println("出货中,请稍后投币");
    }

    @Override
    public void pressButton() {
        System.out.println("出货中,请稍候");
    }

    @Override
    public void dispense() {
        machine.releaseProduct();
        if (machine.getCount() > 0) {
            machine.setState(machine.getNoCoinState());  // 回到「无硬币」
        } else {
            System.out.println("商品已售罄");
            machine.setState(machine.getSoldOutState()); // 切换到「售罄」
        }
    }
}

// 具体状态:售罄
class SoldOutState implements State {
    private VendingMachine machine;

    public SoldOutState(VendingMachine machine) {
        this.machine = machine;
    }

    @Override
    public void insertCoin() {
        System.out.println("商品已售罄");
    }

    @Override
    public void pressButton() {
        System.out.println("商品已售罄");
    }

    @Override
    public void dispense() {
        System.out.println("商品已售罄");
    }
}

// 上下文:自动售货机
class VendingMachine {
    private State noCoinState;
    private State hasCoinState;
    private State soldState;
    private State soldOutState;

    private State currentState;
    private int count;

    public VendingMachine(int count) {
        noCoinState = new NoCoinState(this);
        hasCoinState = new HasCoinState(this);
        soldState = new SoldState(this);
        soldOutState = new SoldOutState(this);

        this.count = count;
        currentState = count > 0 ? noCoinState : soldOutState;
    }

    public void insertCoin() { currentState.insertCoin(); }
    public void pressButton() { currentState.pressButton(); }
    public void dispense() { currentState.dispense(); }

    public void setState(State state) { this.currentState = state; }
    public State getNoCoinState() { return noCoinState; }
    public State getHasCoinState() { return hasCoinState; }
    public State getSoldState() { return soldState; }
    public State getSoldOutState() { return soldOutState; }
    public int getCount() { return count; }

    public void releaseProduct() {
        if (count > 0) {
            System.out.println("出货: 一瓶可乐");
            count--;
        }
    }
}

// 使用
public class Client {
    public static void main(String[] args) {
        VendingMachine machine = new VendingMachine(1);
        machine.insertCoin();   // 投币成功
        machine.pressButton();  // 按钮已按下
        machine.dispense();     // 出货: 一瓶可乐 → 商品已售罄
        machine.insertCoin();   // 商品已售罄
    }
}

经典应用

  • Java 线程状态:NEW → RUNNABLE → BLOCKED / WAITING → TERMINATED
  • TCP 连接状态:ESTABLISHED / CLOSE_WAIT / TIME_WAIT 等状态的行为差异
  • 游戏角色状态:站立、行走、攻击、跳跃等不同状态的行为
  • 工作流引擎:审批流程中待审批/已通过/已驳回等状态流转

如有转载或 CV 请标注本站原文地址