设计模式-状态模式

要理解设计模式中的状态模式,我们可以从其核心思想入手:允许对象在内部状态改变时自动改变其行为,使对象看起来好像修改了它的类。它的本质是将对象的状态封装为独立的状态类,通过状态的切换来控制对象的行为,从而避免大量的条件判断语句(如if-elseswitch-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(); // 电梯开门...(切换到开门状态)
    }
}

输出结果

--- 初始状态:停止且关门 ---
电梯开门...
错误:电梯门未关闭,无法运行
电梯关门...
电梯开始运行...
错误:电梯正在运行,无法开门
电梯停止运行...
电梯开始运行...
电梯停止运行...
电梯开门...

三、状态模式的优点

  1. 消除复杂条件判断:将不同状态下的行为分散到具体状态类中,避免环境类中大量的if-elseswitch-case语句,代码更清晰。
  2. 符合单一职责原则:每个具体状态类只负责对应状态下的行为,职责单一,便于维护。
  3. 易于扩展新状态:新增状态时,只需新增具体状态类并实现抽象状态接口,无需修改环境类或其他状态类(符合“开闭原则”)。
  4. 状态转换清晰:状态转换的逻辑封装在具体状态类中,便于跟踪和理解状态变化流程。

通过这个例子,我们可以清晰看到:状态模式通过将“状态”和“行为”绑定,让对象在不同状态下的行为由对应的状态类自主控制,完美解决了“状态多变且状态依赖行为”的场景问题(如订单状态、设备运行状态、游戏角色状态等)。

posted @ 2025-11-05 10:08  fishyy  阅读(2)  评论(0)    收藏  举报