Java编程之状态模式
引言
“人生如戏,全靠状态。”——设计模式也深知这一点。
一、什么是状态模式(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 Stateclass 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;}@Overridepublic void insertCoin() {System.out.println("硬币已投入。");machine.setState(machine.getHasCoinState());}@Overridepublic void selectProduct() {System.out.println("请先投币!");}@Overridepublic void dispense() {System.out.println("不能发货,请先投币并选择商品。");}
}
已投币状态
public class HasCoinState implements State {private VendingMachine machine;public HasCoinState(VendingMachine machine) {this.machine = machine;}@Overridepublic void insertCoin() {System.out.println("已经有硬币了,请先选择商品。");}@Overridepublic void selectProduct() {System.out.println("商品已选择,正在出货...");machine.setState(machine.getDispensingState());}@Overridepublic void dispense() {System.out.println("请先选择商品!");}
}
出货中状态
public class DispensingState implements State {private VendingMachine machine;public DispensingState(VendingMachine machine) {this.machine = machine;}@Overridepublic void insertCoin() {System.out.println("正在出货,请稍候...");}@Overridepublic void selectProduct() {System.out.println("已经选择了,请等待出货。");}@Overridepublic 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;}@Overridepublic void insertCoin() {System.out.println("商品已售罄,请勿投币。");}@Overridepublic void selectProduct() {System.out.println("无法选择商品,已售罄。");}@Overridepublic 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 & Setterspublic 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种设计模式概览》