设计模式-状态模式
要理解设计模式中的状态模式,我们可以从其核心思想入手:允许对象在内部状态改变时自动改变其行为,使对象看起来好像修改了它的类。它的本质是将对象的状态封装为独立的状态类,通过状态的切换来控制对象的行为,从而避免大量的条件判断语句(如if-else或switch-case)。
一、状态模式的核心角色
状态模式包含3个核心角色,各自职责如下:
| 角色 | 职责描述 |
|---|---|
| 环境类(Context) | 又称“上下文”,持有当前状态的引用,提供接口供客户端调用,内部将状态相关的操作委托给当前状态对象处理。 |
| 抽象状态(State) | 定义状态的接口,声明环境类中与状态相关的操作方法(如状态转换、具体行为)。 |
| 具体状态(ConcreteState) | 实现抽象状态接口,封装该状态下环境类的具体行为,同时可能包含状态转换的逻辑(如切换到其他状态)。 |
二、Java代码演示
我们以“电梯运行状态”为例(电梯有开门、关门、运行、停止四种状态,不同状态下能执行的操作不同,且状态间可相互转换),演示状态模式的实现。
1. 定义抽象状态(State)
声明电梯在不同状态下可执行的操作(开门、关门、运行、停止):
// 抽象状态:电梯状态
public interface ElevatorState {
// 开门操作
void open();
// 关门操作
void close();
// 运行操作
void run();
// 停止操作
void stop();
}
2. 定义具体状态(ConcreteState)
实现抽象状态接口,封装每种状态下的具体行为及状态转换逻辑:
// 具体状态1:开门状态
public class OpenState implements ElevatorState {
// 持有环境类引用(用于状态切换)
private Elevator elevator;
public OpenState(Elevator elevator) {
this.elevator = elevator;
}
@Override
public void open() {
System.out.println("电梯已处于开门状态,无需再次开门");
}
@Override
public void close() {
System.out.println("电梯关门...");
// 关门后切换到“关门状态”
elevator.setState(elevator.getCloseState());
}
@Override
public void run() {
System.out.println("错误:电梯门未关闭,无法运行");
}
@Override
public void stop() {
System.out.println("电梯已停止(门开着),无需再次停止");
}
}
// 具体状态2:关门状态
public class CloseState implements ElevatorState {
private Elevator elevator;
public CloseState(Elevator elevator) {
this.elevator = elevator;
}
@Override
public void open() {
System.out.println("电梯开门...");
// 开门后切换到“开门状态”
elevator.setState(elevator.getOpenState());
}
@Override
public void close() {
System.out.println("电梯已处于关门状态,无需再次关门");
}
@Override
public void run() {
System.out.println("电梯开始运行...");
// 运行后切换到“运行状态”
elevator.setState(elevator.getRunState());
}
@Override
public void stop() {
System.out.println("电梯停止运行(门关闭)...");
// 停止后切换到“停止状态”
elevator.setState(elevator.getStopState());
}
}
// 具体状态3:运行状态
public class RunState implements ElevatorState {
private Elevator elevator;
public RunState(Elevator elevator) {
this.elevator = elevator;
}
@Override
public void open() {
System.out.println("错误:电梯正在运行,无法开门");
}
@Override
public void close() {
System.out.println("电梯运行中已关门,无需再次关门");
}
@Override
public void run() {
System.out.println("电梯已处于运行状态,无需再次启动");
}
@Override
public void stop() {
System.out.println("电梯停止运行...");
// 停止后切换到“停止状态”
elevator.setState(elevator.getStopState());
}
}
// 具体状态4:停止状态
public class StopState implements ElevatorState {
private Elevator elevator;
public StopState(Elevator elevator) {
this.elevator = elevator;
}
@Override
public void open() {
System.out.println("电梯开门...");
// 开门后切换到“开门状态”
elevator.setState(elevator.getOpenState());
}
@Override
public void close() {
System.out.println("电梯已停止且门关闭,无需再次关门");
}
@Override
public void run() {
System.out.println("电梯开始运行...");
// 运行后切换到“运行状态”
elevator.setState(elevator.getRunState());
}
@Override
public void stop() {
System.out.println("电梯已处于停止状态,无需再次停止");
}
}
3. 定义环境类(Context)
持有当前状态的引用,管理所有状态对象,并将操作委托给当前状态:
// 环境类:电梯
public class Elevator {
// 维护所有状态实例(单例,避免重复创建)
private ElevatorState openState;
private ElevatorState closeState;
private ElevatorState runState;
private ElevatorState stopState;
// 当前状态
private ElevatorState currentState;
public Elevator() {
// 初始化所有状态(传入当前电梯实例,用于状态切换)
openState = new OpenState(this);
closeState = new CloseState(this);
runState = new RunState(this);
stopState = new StopState(this);
// 初始状态:停止且关门
currentState = stopState;
}
// 切换当前状态
public void setState(ElevatorState state) {
this.currentState = state;
}
// 暴露状态对象(供具体状态类切换状态)
public ElevatorState getOpenState() {
return openState;
}
public ElevatorState getCloseState() {
return closeState;
}
public ElevatorState getRunState() {
return runState;
}
public ElevatorState getStopState() {
return stopState;
}
// 委托当前状态处理开门操作
public void open() {
currentState.open();
}
// 委托当前状态处理关门操作
public void close() {
currentState.close();
}
// 委托当前状态处理运行操作
public void run() {
currentState.run();
}
// 委托当前状态处理停止操作
public void stop() {
currentState.stop();
}
}
4. 客户端(Client)测试
模拟电梯的一系列操作,验证状态转换是否符合逻辑:
public class Client {
public static void main(String[] args) {
// 创建电梯(环境类)
Elevator elevator = new Elevator();
System.out.println("--- 初始状态:停止且关门 ---");
// 尝试开门
elevator.open(); // 电梯开门...(切换到开门状态)
// 尝试在开门状态下运行(不允许)
elevator.run(); // 错误:电梯门未关闭,无法运行
// 关门
elevator.close(); // 电梯关门...(切换到关门状态)
// 运行
elevator.run(); // 电梯开始运行...(切换到运行状态)
// 尝试在运行状态下开门(不允许)
elevator.open(); // 错误:电梯正在运行,无法开门
// 停止
elevator.stop(); // 电梯停止运行...(切换到停止状态)
// 再次运行
elevator.run(); // 电梯开始运行...(切换到运行状态)
// 再次停止
elevator.stop(); // 电梯停止运行...(切换到停止状态)
// 开门
elevator.open(); // 电梯开门...(切换到开门状态)
}
}
输出结果:
--- 初始状态:停止且关门 ---
电梯开门...
错误:电梯门未关闭,无法运行
电梯关门...
电梯开始运行...
错误:电梯正在运行,无法开门
电梯停止运行...
电梯开始运行...
电梯停止运行...
电梯开门...
三、状态模式的优点
- 消除复杂条件判断:将不同状态下的行为分散到具体状态类中,避免环境类中大量的
if-else或switch-case语句,代码更清晰。 - 符合单一职责原则:每个具体状态类只负责对应状态下的行为,职责单一,便于维护。
- 易于扩展新状态:新增状态时,只需新增具体状态类并实现抽象状态接口,无需修改环境类或其他状态类(符合“开闭原则”)。
- 状态转换清晰:状态转换的逻辑封装在具体状态类中,便于跟踪和理解状态变化流程。
通过这个例子,我们可以清晰看到:状态模式通过将“状态”和“行为”绑定,让对象在不同状态下的行为由对应的状态类自主控制,完美解决了“状态多变且状态依赖行为”的场景问题(如订单状态、设备运行状态、游戏角色状态等)。

浙公网安备 33010602011771号