状态模式是一种行为设计模式,它允许对象在内部状态改变时改变它的行为,仿佛修改了对象的类一样。此模式将状态的逻辑从上下文中分离出来,封装到单独的状态类中,使得状态转换更加清晰和易于管理。
核心概念
- 状态接口(State): 定义所有具体状态类的公共接口,声明处理状态相关行为的方法。
- 具体状态类(Concrete State): 实现状态接口,每一个具体状态类代表对象的一种具体状态,并实现与该状态相关的操作。
- 上下文(Context): 维护一个状态对象的引用,这个状态对象决定了上下文对象的行为。上下文将请求委托给当前状态对象处理,同时上下文可以更改其状态对象,从而改变行为。
JavaScript 示例
假设我们正在开发一个简单的自动贩卖机程序,它有几种状态:空闲、投币、选择商品、退币、分配商品。
// 状态接口
class State {
insertCoin() {
throw new Error("必须在子类中实现insertCoin方法");
}
ejectCoin() {
throw new Error("必须在子类中实现ejectCoin方法");
}
selectProduct() {
throw new Error("必须在子类中实现selectProduct方法");
}
dispenseProduct() {
throw new Error("必须在子类中实现dispenseProduct方法");
}
}
// 具体状态:空闲状态
class IdleState extends State {
constructor(vendingMachine) {
super();
this.vendingMachine = vendingMachine;
}
insertCoin() {
console.log("硬币已接受,等待选择商品。");
this.vendingMachine.setState(new HasCoinState(this.vendingMachine));
}
// 空闲状态下其他方法不做处理
}
// 具体状态:有硬币状态
class HasCoinState extends State {
constructor(vendingMachine) {
super();
this.vendingMachine = vendingMachine;
}
selectProduct() {
console.log("商品分配中...");
this.vendingMachine.setState(new DispensingState(this.vendingMachine));
}
ejectCoin() {
console.log("硬币已退回。");
this.vendingMachine.setState(new IdleState(this.vendingMachine));
}
// 其他方法不做处理
}
// 具体状态:分配商品状态
class DispensingState extends State {
constructor(vendingMachine) {
super();
this.vendingMachine = vendingMachine;
}
dispenseProduct() {
console.log("商品已分配。");
this.vendingMachine.setState(new IdleState(this.vendingMachine));
}
// 其他方法不做处理
}
// 上下文:自动贩卖机
class VendingMachine {
constructor() {
this.state = new IdleState(this);
}
setState(state) {
this.state = state;
}
insertCoin() {
this.state.insertCoin();
}
ejectCoin() {
this.state.ejectCoin();
}
selectProduct() {
this.state.selectProduct();
}
dispenseProduct() {
this.state.dispenseProduct();
}
}
// 使用示例
const vendingMachine = new VendingMachine();
vendingMachine.insertCoin(); // 输出:“硬币已接受,等待选择商品。”
vendingMachine.selectProduct(); // 输出:“商品分配中...”
vendingMachine.dispenseProduct(); // 输出:“商品已分配。”
vendingMachine.ejectCoin(); // 输出:“硬币已退回。” 因为已经分配了商品,所以实际上不会有此输出,此处仅为示例
在这个例子中,VendingMachine
是上下文,它持有一个状态对象(初始为IdleState
)。根据自动贩卖机的不同状态(如插入硬币、选择商品等),它会调用相应状态对象的方法,而这些方法可以改变自动贩卖机的状态,从而改变其行为。这样,状态的改变和行为的实现被封装在状态类中,使得状态转换逻辑更加集中和易于管理。