23种设计模式之【状态机模式】-核心原理与 Java实践

文章目录

状态模式(State Pattern)

状态模式是 23 种设计模式中的一种行为型模式,其核心思想是允许对象在内部状态改变时改变它的行为,使对象看起来好像修改了它的类。这种模式将对象的状态封装为独立的状态类,通过状态切换实现行为的动态变化,避免了使用大量条件判断语句(如if-else或switch-case)。

核心原理

环境类(Context):

持有当前状态的引用,是状态模式的使用者

提供方法供客户端触发状态转换或执行操作

自身不处理状态相关的逻辑,而是委托给当前状态对象
抽象状态(State):

定义所有具体状态的公共接口,声明环境类中可能触发的操作

可以是接口或抽象类,方法对应环境类在不同状态下的行为
具体状态(ConcreteState):

实现抽象状态接口,定义特定状态下的行为逻辑

在执行操作时可能触发状态转换(通过修改环境类的当前状态)

状态模式的核心是 "将状态封装为对象,通过状态对象的切换改变行为",将原本分散在环境类中的状态判断逻辑,拆分到不同的状态类中,使代码更清晰、易维护。

Java 实践示例

以 "订单状态流转" 为例实现状态模式:

订单存在多种状态:待支付、已支付、已发货、已完成、已取消

不同状态下允许的操作不同(如待支付状态可支付或取消,已支付状态可发货等)

通过状态模式封装每种状态的行为及状态转换逻辑

java 复制代码
package com.example.demo;

public class StatePattern {
    public static void main(String[] args) {
        // 创建订单(环境类)
        Order order = new Order();

        System.out.println("=== 初始状态 ===");
        order.getCurrentState();

        // 尝试取消订单(待支付状态可取消)
        System.out.println("\n=== 取消订单 ===");
        order.cancel();
        order.getCurrentState();

        // 重新创建订单并完成全流程
        order = new Order();
        System.out.println("\n=== 新订单流程 ===");
        order.pay();       // 支付
        order.ship();      // 发货
        order.complete();  // 完成
        order.getCurrentState();

        // 尝试在已完成状态执行发货(不允许)
        System.out.println("\n=== 已完成状态执行发货 ===");
        order.ship();
        //=== 初始状态 ===
        //当前订单状态:待支付
        //
        //=== 取消订单 ===
        //订单已取消
        //当前订单状态:已取消
        //
        //=== 新订单流程 ===
        //订单支付成功
        //订单已发货
        //订单已完成
        //当前订单状态:已完成
        //
        //=== 已完成状态执行发货 ===
        //错误:订单已完成,无需发货
    }

    // 抽象状态:订单状态接口
    public interface OrderState {
        // 支付订单
        void pay(Order order);

        // 取消订单
        void cancel(Order order);

        // 发货
        void ship(Order order);

        // 完成订单
        void complete(Order order);

        // 获取状态名称
        String getStateName();
    }

    // 具体状态:待支付
    public static class PendingPaymentState implements OrderState {
        @Override
        public void pay(Order order) {
            // 支付成功,转换为已支付状态
            order.setState(new PaidState());
            System.out.println("订单支付成功");
        }

        @Override
        public void cancel(Order order) {
            // 取消订单,转换为已取消状态
            order.setState(new CancelledState());
            System.out.println("订单已取消");
        }

        @Override
        public void ship(Order order) {
            System.out.println("错误:订单未支付,无法发货");
        }

        @Override
        public void complete(Order order) {
            System.out.println("错误:订单未支付,无法完成");
        }

        @Override
        public String getStateName() {
            return "待支付";
        }
    }

    // 具体状态:已支付
    public static class PaidState implements OrderState {
        @Override
        public void pay(Order order) {
            System.out.println("错误:订单已支付,无需重复支付");
        }

        @Override
        public void cancel(Order order) {
            order.setState(new CancelledState());
            System.out.println("已支付订单取消成功(将安排退款)");
        }

        @Override
        public void ship(Order order) {
            order.setState(new ShippedState());
            System.out.println("订单已发货");
        }

        @Override
        public void complete(Order order) {
            System.out.println("错误:订单未发货,无法完成");
        }

        @Override
        public String getStateName() {
            return "已支付";
        }
    }

    // 具体状态:已发货(其他状态类类似实现)
    public static class ShippedState implements OrderState {
        @Override
        public void pay(Order order) {
            System.out.println("错误:订单已发货,无需支付");
        }

        @Override
        public void cancel(Order order) {
            System.out.println("错误:订单已发货,无法取消");
        }

        @Override
        public void ship(Order order) {
            System.out.println("错误:订单已发货,无需重复发货");
        }

        @Override
        public void complete(Order order) {
            order.setState(new CompletedState());
            System.out.println("订单已完成");
        }

        @Override
        public String getStateName() {
            return "已发货";
        }
    }

    // 具体状态:已完成
    public static class CompletedState implements OrderState {
        // 实现所有方法,已完成状态下大部分操作不允许
        @Override
        public void pay(Order order) {
            System.out.println("错误:订单已完成,无需支付");
        }

        @Override
        public void cancel(Order order) {
            System.out.println("错误:订单已完成,无法取消");
        }

        @Override
        public void ship(Order order) {
            System.out.println("错误:订单已完成,无需发货");
        }

        @Override
        public void complete(Order order) {
            System.out.println("错误:订单已完成,无需重复操作");
        }

        @Override
        public String getStateName() {
            return "已完成";
        }
    }

    // 具体状态:已取消
    public static class CancelledState implements OrderState {
        // 实现所有方法,已取消状态下大部分操作不允许
        @Override
        public void pay(Order order) {
            System.out.println("错误:订单已取消,无法支付");
        }

        @Override
        public void cancel(Order order) {
            System.out.println("错误:订单已取消,无需重复取消");
        }

        @Override
        public void ship(Order order) {
            System.out.println("错误:订单已取消,无法发货");
        }

        @Override
        public void complete(Order order) {
            System.out.println("错误:订单已取消,无法完成");
        }

        @Override
        public String getStateName() {
            return "已取消";
        }
    }

    // 环境类:订单
    public static class Order {
        // 持有当前状态的引用
        private OrderState currentState;

        // 初始化订单为待支付状态
        public Order() {
            this.currentState = new PendingPaymentState();
        }

        // 设置当前状态(供状态类调用以实现状态转换)
        public void setState(OrderState state) {
            this.currentState = state;
        }

        // 委托当前状态处理支付操作
        public void pay() {
            currentState.pay(this);
        }

        // 委托当前状态处理取消操作
        public void cancel() {
            currentState.cancel(this);
        }

        // 委托当前状态处理发货操作
        public void ship() {
            currentState.ship(this);
        }

        // 委托当前状态处理完成操作
        public void complete() {
            currentState.complete(this);
        }

        // 获取当前状态名称
        public void getCurrentState() {
            System.out.println("当前订单状态:" + currentState.getStateName());
        }
    }
}

状态模式的特点

  • 优点:
    消除大量条件判断:将状态相关的逻辑分散到不同状态类,替代冗长的if-else或switch-case
    状态转换清晰:每个状态类负责自身的状态转换逻辑,职责单一
    易于扩展:新增状态只需添加新的状态类,符合开闭原则
    状态封装性好:状态的细节被隐藏在具体状态类中,环境类无需了解
  • 缺点:
    类数量增加:每个状态对应一个类,状态较多时会导致类数量膨胀
    状态转换依赖环境类:状态类需要持有环境类引用才能实现状态转换,增加了耦合

与策略模式的区别:

状态模式:状态的切换由对象内部状态决定,策略通常由客户端主动设置

策略模式:关注不同算法的替换,状态模式关注状态变化导致的行为变化

状态模式的应用场景

  • 状态流转明确的业务对象:
    订单状态、流程状态、审批状态等有明确流转规则的对象
    例如:电商订单(待支付→已支付→已发货→已完成)、请假审批流程
  • 有限状态机(FSM):
    具有有限个状态且状态间转换规则明确的系统
    例如:电梯控制(开门→关门→运行→停止)、交通信号灯(红→黄→绿)
  • 游戏开发:
    游戏角色状态( idle→行走→攻击→受伤→死亡)
    游戏场景状态(加载中→正常→暂停→结束)
  • UI 组件状态:
    按钮状态(可用→禁用→选中→未选中)
    表单输入状态(未编辑→编辑中→验证通过→验证失败)

状态模式特别适合对象行为随状态变化而变化,且状态数量较多、转换逻辑复杂的场景。它通过将状态逻辑封装为独立对象,使系统更易于维护和扩展,是处理状态流转的最佳实践之一。

相关推荐
无名指的等待7123 小时前
Redisson的Lock和TryLock的区别
java·开发语言·数据库
new_daimond4 小时前
Apache Shiro 技术详解
java·apache
yuriy.wang4 小时前
Spring IOC源码篇六 核心方法obtainFreshBeanFactory.parseCustomElement
java·后端·spring
.鸣4 小时前
idea学习日记10: 字符串相关类的底层原理
java·学习
在未来等你4 小时前
Kafka面试精讲 Day 24:Spring Kafka开发实战
java·spring boot·面试·kafka·消息队列·spring kafka·@kafkalistener
龙茶清欢4 小时前
1、Lombok入门与环境配置:理解Lombok作用、配置IDE与构建工具
java·spring boot·spring cloud
龙茶清欢5 小时前
2、Nginx 与 Spring Cloud Gateway 详细对比:定位、场景与分工
java·运维·spring boot·nginx·spring cloud·gateway
Eoch775 小时前
HashMap夺命十连问,你能撑到第几轮?
java·后端
云动雨颤5 小时前
程序出错瞎找?教你写“会说话”的错误日志,秒定位原因
java·运维·php