Java编程之状态模式

发布于:2025-07-02 ⋅ 阅读:(17) ⋅ 点赞:(0)

引言

“人生如戏,全靠状态。”——设计模式也深知这一点。


一、什么是状态模式(State Pattern)

状态模式是一种行为型设计模式,允许对象在内部状态改变时,改变它的行为。也就是说,看起来像是修改了它的类

通俗解释

就像一只电风扇,有关机状态低速状态高速状态。你按下按钮,它就在不同的状态间切换。状态决定了电风扇的行为


二、示例讲解:

本篇我们以“自动售货机 Vending Machine”为例。它可能处于以下状态:

  • 等待投币
  • 已投币,等待选择
  • 正在出货
  • 售罄

用户的操作行为(如投币、选择商品、取货)会根据当前状态产生不同的响应。


三、UML 图结构(PlantUML):

@startuml
interface State {
  +insertCoin()
  +selectProduct()
  +dispense()
}

class WaitingForCoin implements State
class HasCoin implements State
class Dispensing implements State
class SoldOut implements State

class VendingMachine {
  -state: State
  +setState(s: State)
  +insertCoin()
  +selectProduct()
  +dispense()
}

State <|.. WaitingForCoin
State <|.. HasCoin
State <|.. Dispensing
State <|.. SoldOut
VendingMachine --> State
@enduml

在这里插入图片描述


四、Java 实现代码

状态接口

public interface State {
    void insertCoin();
    void selectProduct();
    void dispense();
}

具体状态实现

等待投币状态

public class WaitingForCoinState implements State {
    private VendingMachine machine;

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

    @Override
    public void insertCoin() {
        System.out.println("硬币已投入。");
        machine.setState(machine.getHasCoinState());
    }

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

    @Override
    public void dispense() {
        System.out.println("不能发货,请先投币并选择商品。");
    }
}

已投币状态

public class HasCoinState implements State {
    private VendingMachine machine;

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

    @Override
    public void insertCoin() {
        System.out.println("已经有硬币了,请先选择商品。");
    }

    @Override
    public void selectProduct() {
        System.out.println("商品已选择,正在出货...");
        machine.setState(machine.getDispensingState());
    }

    @Override
    public void dispense() {
        System.out.println("请先选择商品!");
    }
}

出货中状态

public class DispensingState implements State {
    private VendingMachine machine;

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

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

    @Override
    public void selectProduct() {
        System.out.println("已经选择了,请等待出货。");
    }

    @Override
    public void dispense() {
        System.out.println("出货完成!");
        if (machine.getProductCount() > 0) {
            machine.setState(machine.getWaitingForCoinState());
        } else {
            System.out.println("商品售罄!");
            machine.setState(machine.getSoldOutState());
        }
    }
}

售罄状态

public class SoldOutState implements State {
    private VendingMachine machine;

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

    @Override
    public void insertCoin() {
        System.out.println("商品已售罄,请勿投币。");
    }

    @Override
    public void selectProduct() {
        System.out.println("无法选择商品,已售罄。");
    }

    @Override
    public void dispense() {
        System.out.println("无法出货,商品售罄。");
    }
}

状态持有者:VendingMachine 类

public class VendingMachine {
    private State waitingForCoinState;
    private State hasCoinState;
    private State dispensingState;
    private State soldOutState;

    private State currentState;
    private int productCount;

    public VendingMachine(int initialCount) {
        waitingForCoinState = new WaitingForCoinState(this);
        hasCoinState = new HasCoinState(this);
        dispensingState = new DispensingState(this);
        soldOutState = new SoldOutState(this);

        this.productCount = initialCount;
        this.currentState = initialCount > 0 ? waitingForCoinState : soldOutState;
    }

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

    public void selectProduct() {
        currentState.selectProduct();
    }

    public void dispense() {
        currentState.dispense();
        if (productCount > 0 && currentState == dispensingState) {
            productCount--;
        }
    }

    // Getters & Setters
    public void setState(State state) {
        this.currentState = state;
    }

    public State getWaitingForCoinState() { return waitingForCoinState; }
    public State getHasCoinState() { return hasCoinState; }
    public State getDispensingState() { return dispensingState; }
    public State getSoldOutState() { return soldOutState; }
    public int getProductCount() { return productCount; }
}

测试代码

public class Main {
    public static void main(String[] args) {
        VendingMachine machine = new VendingMachine(2);

        machine.insertCoin();
        machine.selectProduct();
        machine.dispense();

        machine.insertCoin();
        machine.selectProduct();
        machine.dispense();

        // 尝试再买一次
        machine.insertCoin();
        machine.selectProduct();
        machine.dispense();
    }
}

五、总结:状态模式的优缺点

优点:

  • 封装状态转换逻辑,消除了大量 if-else
  • 新状态扩展易如反掌
  • 状态切换透明,对外接口不变

缺点:

  • 类数量变多(每个状态一个类)
  • 状态之间可能耦合紧密

六、适用场景

  • 对象行为依赖于状态变化(如:文档编辑器、交通灯、媒体播放器)
  • 状态可枚举、行为可切换,但不适合用大量 if/else 处理

七、参考

《23种设计模式概览》

在这里插入图片描述


网站公告

今日签到

点亮在社区的每一天
去签到