设计模式-状态模式

一、什么是状态模式

状态模式是一种行为设计模式,使用状态模式,能够在一个对象内部状态变化时改变它的行为,使其看起来就像改变自身的类一样。
核心点:区分事物内部的状态,把事物的每种状态都封装成单独的类,跟此状态有关的行为都被封装在这个类的内部,当对象的状态改变时,它的行为也会随之改变。

二、状态模式的主要构成

  1. 环境类(Context)角色:也叫上下文,定义类客户端需要的接口,维护了一个当前状态,并将状态相关的操作委托给当前的状态对象来处理;
  2. 抽象状态(State)角色:定义一个状态接口,用于封装状态所对应的行为;
  3. 具体状态(Concrete State)角色:实现抽象状态对应的行为,用于切换状态

三、状态模式代码示例

假如有一个抽奖奖励场景,奖励存在多种状态,分别为未激活状态、已激活状态、已暂停状态和已结束状态,各个状态之间会根据相关方法或者时间触发到转换到其他状态,状态转换规则如下图所示

处于未激活状态 ,它会根据开始时间自动激活奖励,转移到已激活状态 ,处于已激活状态的奖励,管理员可以将抽奖活动进行暂停,此时奖励会进入已暂停状态 ,处于已暂停状态的奖励,又可以手动开启,进入已激活状态;处于已激活状态,会随着奖品的发放完成,进入到已结束状态,在不同的状态下,奖励对应的行为也是不同的。

假如没有使用状态模式,我们通常的做法是使用多个条件运算符if else或switch来实现,代码示例如下:

java 复制代码
public class Reward {
    private enum State {
        INACTIVE, ACTIVE, PAUSED, FINISHED
    }

    private State currentState;

    public Reward() {
        currentState = State.INACTIVE; // 初始状态为未激活
    }

    public void activate() {
        switch (currentState) {
            case INACTIVE:
                System.out.println("奖励已激活");
                currentState = State.ACTIVE;
                break;
            case ACTIVE:
                System.out.println("奖励已激活,无需再次激活");
                break;
            case PAUSED:
                System.out.println("奖励已激活");
                break;
            case FINISHED:
                System.out.println("奖励已结束,无法激活");
                break;
        }
    }

    public void pause() {
        switch (currentState) {
            case INACTIVE:
                System.out.println("奖励未激活,不能暂停");
                break;
            case ACTIVE:
                System.out.println("奖励已暂停");
                currentState = State.PAUSED;
                break;
            case PAUSED:
                System.out.println("奖励已暂停,无需再次暂停");
                break;
            case FINISHED:
                System.out.println("奖励已结束,无法暂停");
                break;
        }
    }

    public void finish() {
        switch (currentState) {
            case INACTIVE:
                System.out.println("奖励已结束");
                break;
            case ACTIVE:
                System.out.println("奖励已结束");
                currentState = State.FINISHED;
                break;
            case PAUSED:
                System.out.println("奖励已结束");
                currentState = State.FINISHED;
                break;
            case FINISHED:
                System.out.println("奖励已结束,无需再次结束");
                break;
        }
    }

    public static void main(String[] args) {
        Reward reward = new Reward();

        // 未激活状态
        reward.activate();
        reward.pause();
        reward.finish();

        // 激活状态
        reward.activate();
        reward.pause();
        reward.finish();

        // 暂停状态
        reward.pause();
        reward.finish();

        // 结束状态
        reward.finish();
        reward.activate();
        reward.pause();
        reward.finish();
    }
}

存在的问题:由于我们预先定义了枚举类的一些状态,后面会随着业务规则变动,又会增加状态以及状态之间的转换规则,则传统的if else结构,显得扩展性不足,代码会变得臃肿不好维护。

使用状态模式实现如下:

java 复制代码
public interface RewardState {
    void activate();
    void pause();
    void finish();
}
public class InactiveState implements RewardState{
    @Override
    public void activate() {
        System.out.println("奖励已激活");
    }
    @Override
    public void pause() {
        System.out.println("奖励未激活,不能暂停");
    }
    @Override
    public void finish() {
        System.out.println("奖励未激活,不能结束");
    }
}
public class ActiveState implements RewardState{
    @Override
    public void activate() {
        System.out.println("奖励已激活,无需再次激活");
    }
    @Override
    public void pause() {
        System.out.println("奖励已暂停");
    }
    @Override
    public void finish() {
        System.out.println("奖励已结束");
    }
}
public class PausedState implements RewardState{

    @Override
    public void activate() {
        System.out.println("奖励已激活");
    }
    @Override
    public void pause() {
        System.out.println("奖励已暂停,无需再次暂停");
    }
    @Override
    public void finish() {
        System.out.println("奖励已结束");
    }
}
public class FinishedState implements RewardState{
    @Override
    public void activate() {
        System.out.println("奖励已结束,无法再次激活");
    }
    @Override
    public void pause() {
        System.out.println("奖励已结束,无法暂停");
    }
    @Override
    public void finish() {
        System.out.println("奖励已结束,无需再次结束");
    }
}
public class RewardContext {
    private RewardState state;

    public RewardContext() {
        state = new InactiveState(); // 初始状态为未激活
    }

    public void setState(RewardState state) {
        this.state = state;
    }

    public void activate() {
        state.activate();
    }

    public void pause() {
        state.pause();
    }

    public void finish() {
        state.finish();
    }
}

// Demo测试
public class Main {
    public static void main(String[] args) {
        RewardContext context = new RewardContext();

        // 未激活状态
        context.activate();
        context.pause();
        context.finish();

        // 激活状态
        context.setState(new ActiveState());
        context.activate();
        context.pause();
        context.finish();

        // 暂停状态
        context.setState(new PausedState());
        context.activate();
        context.pause();
        context.finish();

        // 结束状态
        context.setState(new FinishedState());
        context.activate();
        context.pause();
        context.finish();
    }
}

执行结果:

四、状态模式的应用

  1. 订单处理系统,订单可以处于不同的状态,如已下单、待支付、已支付、待发货、已发货、已完成等。状态模式可以用来管理订单之间状态的转换和对应的执行的操作。
  2. 工作流引擎,在工作流管理中,任务可以处于不同的状态,如待处理、处理中、处理完成等等。
  3. 游戏角色状态,游戏中的人物角色可以处于不同的状态,例如站立状态、行走状态、跑动状态、攻击状态等
  4. 电梯控制系统,电梯可以处于不同的状态,例如停止状态、运行状态、上行、下行、故障等等。

五、状态模式优缺点

优点:

  1. 代码可读性好,状态之间的转换封装到了具体类中,可以清晰管理状态之间的转换;
  2. 可维护性好,扩展性强,如添加和删除状态比较方便,不会影响原有状态类的代码;
  3. 符合开闭原则: 状态模式使得状态类可以独立变化和扩展,符合开闭原则,对修改封闭,对扩展开放。

缺点:

  1. . 增加代码中对象和类的个数,增加了系统实现的复杂性;

  2. 状态间的转换: 状态之间的转换可能比较复杂,需要仔细设计状态之间的转换关系;

  3. 状态模式的适用场景有限: 如果一个对象的状态很少改变,或者状态转换比较简单,使用状态模式可能会显得过于繁琐。

参考:订单及其状态机的设计实现

相关推荐
Charlie__ZS3 分钟前
若依框架去掉Redis
java·redis·mybatis
tianchang29 分钟前
SSR 深度解析:从原理到实践的完整指南
前端·vue.js·设计模式
咖啡啡不加糖36 分钟前
RabbitMQ 消息队列:从入门到Spring Boot实战
java·spring boot·rabbitmq
玩代码43 分钟前
Java线程池原理概述
java·开发语言·线程池
NE_STOP1 小时前
SpringBoot--如何给项目添加配置属性及读取属性
java
水果里面有苹果1 小时前
20-C#构造函数--虚方法
java·前端·c#
%d%d21 小时前
python 在运行时没有加载修改后的版本
java·服务器·python
金銀銅鐵1 小时前
[Kotlin] 单例对象是如何实现的?
java·kotlin
泰勒疯狂展开1 小时前
Java研学-MongoDB(三)
java·开发语言·mongodb
zzywxc7871 小时前
AI技术通过提示词工程(Prompt Engineering)正在深度重塑职场生态和行业格局,这种变革不仅体现在效率提升,更在重构人机协作模式。
java·大数据·开发语言·人工智能·spring·重构·prompt