【设计模式】行为型-状态模式

发布于:2024-06-30 ⋅ 阅读:(15) ⋅ 点赞:(0)

在变幻的时光中,状态如诗篇般细腻流转。

一、可调节的灯光

场景假设:我们有一个电灯,它可以被打开和关闭。用户可以通过一个开关来改变电灯的状态。

/**
 * 表示可以开关的灯的类。
 */
public class Light {
    private String state; // 灯的当前状态,可能是"ON"或者"OFF"

    /**
     * 构造方法,初始化灯的状态为"OFF"。
     */
    public Light() {
        this.state = "OFF";
    }

    /**
     * 开关灯的状态。
     * 如果灯当前为"OFF",则将其改为"ON"并打印"灯已打开"。
     * 如果灯当前为"ON",则将其改为"OFF"并打印"灯已关闭"。
     */
    public void switchState() {
        if ("OFF".equals(state)) {
            state = "ON";
            System.out.println("灯已打开");
        } else {
            state = "OFF";
            System.out.println("灯已关闭");
        }
    }
}

上面的代码虽然能够实现需求,因为只有两种状态。但是,如果电灯有更多的状态,比如“调暗”、“调亮”、“闪烁”等,那么 switchState 方法就会变得非常复杂,充满了 if-else 语句。这将使代码难以阅读和维护。

二、状态模式

状态模式(State Pattern)是一种行为型设计模式,它允许对象在其内部状态发生改变时改变其行为,使其看起来像是改变了其类。状态模式的关键思想是将对象的行为封装在不同的状态对象中,并且在状态转换时可以动态地改变对象的行为。

三、状态模式的核心组件

状态模式的核心组件包括以下几个角色:

  1. Context(上下文):上下文是拥有状态的对象。它定义了客户端感兴趣的接口,并且维护一个当前状态对象,这个状态对象定义了当前的状态和相应的行为。Context 可以通过状态对象来改变它的行为。
  2. State(状态):状态是一个接口或者抽象类,它封装了与 Context 的一个特定状态相关的行为。在 State 接口或者抽象类中定义了所有具体状态类所共享的方法,这些方法的实现将依赖于当前状态。通常,这些方法处理与状态相关的操作,如请求或者事件。
  3. ConcreteState(具体状态):具体状态类实现了 State 接口或者继承了 State 抽象类。每个具体状态类实现了与 Context 的一个状态相关的行为。例如,在电梯系统中,可能会有开门状态、关门状态、运行状态和停止状态等具体状态类。

在这里插入图片描述

这个类图展示了状态模式的核心组成部分:

  • State 接口定义了 doAction(Context) 方法,表示所有具体状态类(OpenState 和 CloseState)需要实现的方法。
  • OpenState 和 CloseState 类分别实现了 State 接口,并实现了 doAction(Context) 方法来处理具体的状态操作。
  • Context 类包含一个状态接口类型的私有成员变量 state,通过 setState(State) 方法设置当前的状态,并通过 request() 方法执行当前状态的动作。

四、运用状态模式

场景假设:我们有一个电灯,它可以被打开和关闭。用户可以通过一个开关来改变电灯的状态。电灯有更多的状态,比如“调暗”、“调亮”、“闪烁”等。

  1. 定义状态接口:首先,我们需要定义一个状态接口,该接口声明了所有具体状态类需要实现的方法。在我们的例子中,我们可以定义一个 LightState 接口,该接口有一个 switchState 方法。

    // 定义状态接口
    public interface LightState {
        // 声明改变状态的方法,接收一个 Light 对象作为参数
        void switchState(Light light);
    }
    
  2. 创建具体状态类:然后,我们需要为每种状态创建一个具体的状态类。这些类需要实现状态接口,并实现接口中声明的方法。在我们的例子中,我们可以创建 OnState 和 OffState 类。

    // 创建具体状态类:打开状态
    public class OnState implements LightState {
        @Override
        public void switchState(Light light) {
            // 改变 Light 对象的状态为 DimState
            light.setState(new DimState());
            System.out.println("Light is dimmed");
        }
    }
    
    // 创建具体状态类:关闭状态
    public class OffState implements LightState {
        @Override
        public void switchState(Light light) {
            // 改变 Light 对象的状态为 OnState
            light.setState(new OnState());
            System.out.println("Light is turned ON");
        }
    }
    
    // 创建具体状态类:调暗状态
    public class DimState implements LightState {
        @Override
        public void switchState(Light light) {
            // 改变 Light 对象的状态为 BlinkState
            light.setState(new BlinkState());
            System.out.println("Light is blinking");
        }
    }
    
    // 创建具体状态类:闪烁状态
    public class BlinkState implements LightState {
        @Override
        public void switchState(Light light) {
            // 改变 Light 对象的状态为 OffState
            light.setState(new OffState());
            System.out.println("Light is turned OFF");
        }
    }
    
  3. 在上下文类中使用状态:最后,我们需要在上下文类中使用这些状态。上下文类维护一个对状态对象的引用,该引用可以在运行时更改。在我们的例子中,Light 类就是上下文类。

    // 创建上下文类:电灯
    public class Light {
        // Light 对象维护一个对状态对象的引用
        private LightState state;
    
        public Light() {
            // 初始状态为 OffState
            this.state = new OffState();
        }
    
        // 设置 Light 对象的状态
        public void setState(LightState state) {
            this.state = state;
        }
    
        // 切换 Light 对象的状态
        public void switchState() {
            state.switchState(this);
        }
    }
    
  4. 客户端:通过客户端测试

    public class Client {
        public static void main(String[] args) {
            // 创建一个 Light 对象
            Light light = new Light();
    
            // 切换 Light 对象的状态
            light.switchState(); // 打开电灯
            light.switchState(); // 调暗电灯
            light.switchState(); // 电灯开始闪烁
            light.switchState(); // 关闭电灯
        }
    }
    

五、状态模式的应用场景

状态模式在许多场景中都非常有用,特别是当一个对象的行为取决于其状态,并且它必须在运行时根据状态改变其行为时。以下是一些常见的应用场景:

  1. 用户界面(UI):在许多用户界面中,元素的行为会根据其状态(如禁用、选中、悬停等)而改变。状态模式可以帮助我们管理这些状态,并使状态转换的逻辑更加清晰。
  2. 游戏开发:在游戏开发中,角色的行为通常会根据其状态(如站立、跑动、跳跃、攻击等)而改变。使用状态模式,我们可以为每种状态创建一个状态类,使得代码更易于理解和维护。
  3. 工作流引擎:在工作流引擎中,任务的行为会根据其状态(如新建、进行中、已完成等)而改变。状态模式可以帮助我们管理这些状态,并使状态转换的逻辑更加清晰。
  4. 网络连接:网络连接的行为会根据其状态(如打开、关闭、等待等)而改变。状态模式可以帮助我们管理这些状态,并使状态转换的逻辑更加清晰。

六、小结

状态模式是一种优秀的设计模式,适用于那些对象行为会随着内部状态变化而变化的情况。它通过将对象的状态和行为分离,使得系统更加灵活、易于理解和扩展。

推荐阅读

  1. 深入探究 Spring Boot Starter:从概念到实践
  2. 深入理解 Java 中的 volatile 关键字
  3. OAuth 2.0:现代应用程序的授权标准
  4. Spring 三级缓存
  5. 深入了解 MyBatis 插件:定制化你的持久层框架