状态模式(State Pattern)是一种行为型设计模式,其主要目的是允许一个对象在其内部状态改变时改变其行为,看起来就像是改变了对象的类。状态模式将对象的状态封装成独立的类,使得对象状态的变化可以独立于对象本身的变化。
状态模式的重点是在其内部可以自动切换到需要的状态对象,新的状态对象拥有新的行为,比如一个自动售货机,它可以处于三种状态:正常运行 、缺货 、维护中。在正常运行状态下,它可以接受货币并提供商品;在缺货状态下,它不接受货币并显示"抱歉,商品已售罄";在维护中状态下,它完全关闭,不接受货币也不提供商品。
这里,自动售货机的行为取决于它的状态。状态模式允许售货机在不同的状态下有不同的行为,而且状态可以在运行时动态改变,比如当库存耗尽时,自动售货机的状态会从正常运行变为缺货状态。这样,状态模式使得系统能够更加灵活地应对不同的情况,同时也使得代码更加清晰易懂。
主要角色:
-
上下文(Context): 定义了客户端感兴趣的接口,并且维护一个具体状态的实例,可以根据当前状态调用不同的具体状态。
-
状态(State): 定义了一个接口,封装了与上下文的一个特定状态相关的行为。
-
具体状态(Concrete State): 实现了状态接口,包含了与特定状态相关的行为。
示例:
下面是一个简单的 Java 代码示例,实现了自动售货机的状态模式:
java
package com.luke.designpatterns.statePattern;
// 状态接口
interface VendingMachineState {
void pay();
void getProduct();
}
// 具体状态类 - 正常运行状态
class NormalState implements VendingMachineState {
@Override
public void pay() {
System.out.println("扫码购买产品!");
}
@Override
public void getProduct() {
System.out.println("购买成功!");
}
}
// 具体状态类 - 缺货状态
class SoldOutState implements VendingMachineState {
@Override
public void pay() {
System.out.println("抱歉,商品已售罄,扫码失败");
}
@Override
public void getProduct() {
System.out.println("抱歉,商品已售罄");
}
}
// 具体状态类 - 维护中状态
class MaintenanceState implements VendingMachineState {
@Override
public void pay() {
System.out.println("机器正在维护,无法扫码支付");
}
@Override
public void getProduct() {
System.out.println("机器正在维护");
}
}
// 环境类 - 自动售货机
class VendingMachine {
private VendingMachineState currentState;
public VendingMachine() {
// 初始状态为正常运行状态
currentState = new NormalState();
}
public void setState(VendingMachineState newState) {
this.currentState = newState;
}
public void insertCoin() {
currentState.pay();
}
public void dispenseItem() {
currentState.getProduct();
}
}
// 客户端代码
public class StatePatternExample {
public static void main(String[] args) {
VendingMachine vendingMachine = new VendingMachine();
vendingMachine.insertCoin();
vendingMachine.dispenseItem();
// 模拟缺货情况
vendingMachine.setState(new SoldOutState());
vendingMachine.insertCoin();
vendingMachine.dispenseItem();
// 模拟维护中情况
vendingMachine.setState(new MaintenanceState());
vendingMachine.insertCoin();
vendingMachine.dispenseItem();
}
}
在这个例子中,VendingMachine
类是环境类,负责维护当前的状态,并根据当前状态调用相应的方法。不同的状态由实现了 VendingMachineState
接口的具体状态类来表示,每个具体状态类实现了在特定状态下的行为。客户端代码可以通过调用 insertCoin
和 dispenseItem
方法与自动售货机进行交互。通过改变状态,自动售货机在不同的情况下表现出不同的行为。
适用场景
状态模式适用于以下场景:
-
对象的行为依赖于其状态,并且可以在运行时根据状态改变而改变行为。
- 例如,一个文档编辑器,它可以处于编辑模式、预览模式和保存模式。不同模式下,工具栏和菜单的行为会有所不同。
-
对象有大量的条件语句来管理多个状态,并且这些条件语句使得代码难以维护和扩展。
- 如果在代码中存在很多类似的if-else语句来处理对象的不同状态,状态模式可以帮助将这些状态的处理逻辑分散到不同的状态类中,使代码更清晰、可读性更好。
-
一个对象的状态转换在运行时可以发生,并且需要封装状态的变化。
- 例如,在一个工作流应用中,一个任务可能有多个状态(待处理、处理中、已完成等),任务的状态可以在运行时发生变化,状态模式可以用来管理这些变化。
-
有些状态共享相同的行为,但在不同的状态下可能需要进行不同的处理。
- 如果有几个状态在执行相同的操作时有共通的行为,但在细节上有所不同,状态模式可以减少重复代码,通过在每个状态类中实现相应的细节,使得代码更加模块化。
-
状态模式可以用于消除大量的条件性语句,提高代码的可维护性和可读性。
- 当一个对象有多个状态,而这些状态在其行为上有明显的不同,使用状态模式可以将状态之间的转换和处理逻辑封装在独立的类中,使得代码更易于理解和维护。