Java设计模式之《状态模式》

发布于:2025-08-29 ⋅ 阅读:(11) ⋅ 点赞:(0)

目录

1、状态模式

1.1、介绍

1.2、设计背景

1.3、适用场景

2、实现

2.1、if-else实现

2.2、状态模式实现

2.3、最终版

1、关于if-else的优化

2、状态模式下的优化

3、ArrayList 配置“状态流”

3、总结


前言

关于Java的设计模式分类如下:

对于状态模式的组件组成,如下所示:


1、状态模式

1.1、介绍

允许一个对象在其内部状态发生改变时,行为也随之改变,看起来就像对象修改了它的类。

  • 状态模式就是把“状态”封装成独立的类,不同状态下执行不同的逻辑
  • 状态切换由对象自己控制,而不是外部用 if-else/switch来判断

1.2、设计背景

问题场景:

if (status == "UNPAID") { /* 处理支付 */ }
else if (status == "PAID") { /* 处理发货 */ }
else if (status == "SHIPPED") { /* 处理收货 */ }
  • 每加一个状态,要修改这段代码
  • 状态切换逻辑和行为混在一起,难维护

状态模式的好处:

  • 每个状态的逻辑单独放在一个类中
  • 遵循 开闭原则(新增状态只加类,不改原来代码)
  • 状态的切换由对象自身控制,不依赖外部复杂判断

两者对比,如下所示:

1.3、适用场景

在项目中常用的场景如下:

  • Spring StateMachine(状态机框架)
  • 订单系统:未支付 → 已支付 → 已发货 → 已完成
  • 工作流引擎(Flowable、Activiti)
  • Netty Channel 状态:UNREGISTERED → REGISTERED → ACTIVE → INACTIVE

💡 因此:

  • 如果状态很少且不会变,可以用 if-else
  • 如果状态多、变化频繁,并且有复杂行为 => 用状态模式

2、实现

2.1、if-else实现

public class Order {
    public static final int UNPAID = 0;
    public static final int PAID = 1;
    public static final int SHIPPED = 2;
    public static final int DONE = 3;

    private int status = UNPAID;

    public void process() {
        if (status == UNPAID) {
            System.out.println("当前订单未支付,执行支付逻辑...");
            status = PAID;
        } else if (status == PAID) {
            System.out.println("订单已支付,执行发货逻辑...");
            status = SHIPPED;
        } else if (status == SHIPPED) {
            System.out.println("订单已发货,执行收货逻辑...");
            status = DONE;
        } else if (status == DONE) {
            System.out.println("订单已完成");
        } else {
            System.out.println("未知订单状态");
        }
    }
}

测试:

public class Test {
    public static void main(String[] args) {
        Order order = new Order();
        order.process(); // 支付
        order.process(); // 发货
        order.process(); // 收货
        order.process(); // 已完成
    }
}

这种方式短期内可用,但问题比较明显:

1、集中式 if-else

所有状态逻辑都在一个方法里面,方法不断膨胀,维护困难。

2、违反开闭原则

新增状态时必须修改这个方法的代码,容易引入 bug。

3、状态切换逻辑分散

可能在多个方法都有类似的 if-else,改动的时候要到处找。

4、可读性差

状态和行为耦合得很紧,不直观。

2.2、状态模式实现

订单状态流转

1、定义状态接口

public interface OrderState {
    void handle(OrderContext context);
}

2、具体状态类

public class UnpaidState implements OrderState {
    public void handle(OrderContext context) {
        System.out.println("当前订单未支付,执行支付逻辑...");
        context.setState(new PaidState()); // 切换状态
    }
}

public class PaidState implements OrderState {
    public void handle(OrderContext context) {
        System.out.println("订单已支付,执行发货逻辑...");
        context.setState(new ShippedState());
    }
}

public class ShippedState implements OrderState {
    public void handle(OrderContext context) {
        System.out.println("订单已发货,执行收货逻辑...");
        context.setState(new DoneState());
    }
}

public class DoneState implements OrderState {
    public void handle(OrderContext context) {
        System.out.println("订单已完成");
    }
}

3、环境类

public class OrderContext {
    private OrderState state;
    public OrderContext(OrderState state) { this.state = state; }
    public void setState(OrderState state) { this.state = state; }
    public void request() { state.handle(this); }
}

测试

public class Test {
    public static void main(String[] args) {
        OrderContext order = new OrderContext(new UnpaidState());
        order.request(); // 支付
        order.request(); // 发货
        order.request(); // 收货
        order.request(); // 已完成
    }
}

输出:
当前订单未支付,执行支付逻辑...
订单已支付,执行发货逻辑...
订单已发货,执行收货逻辑...
订单已完成

基于前面的if-else和状态模式都需要多次去调用方法,因此可以对调用次数进行优化。

2.3、最终版

1、关于if-else的优化

public class Order {
    private int status = 0;

    private static final List<Integer> PROCESS_LIST = List.of(
        0, // UNPAID
        1, // PAID
        2, // SHIPPED
        3  // DONE
    );

    public void process() {
        if (status == 0) {
            System.out.println("未支付 -> 支付");
            status = 1;
        } else if (status == 1) {
            System.out.println("已支付 -> 发货");
            status = 2;
        } else if (status == 2) {
            System.out.println("已发货 -> 收货");
            status = 3;
        } else {
            System.out.println("订单完成");
        }
    }

    public static void main(String[] args) {
        Order order = new Order();
        PROCESS_LIST.forEach(s -> order.process());
    }
}

这样避免了写 4 行 order.process(),但 逻辑依旧集中在一个方法里,只是调用更“批量”了。

2、状态模式下的优化

状态模式下,我们可以更灵活地用集合来管理状态流转过程,而且不用去写 if-else。

例子:

interface State {
    void handle(OrderContext ctx);
}

class UnpaidState implements State {
    public void handle(OrderContext ctx) {
        System.out.println("当前订单未支付 -> 执行支付逻辑...");
        ctx.setState(new PaidState());
    }
}

class PaidState implements State {
    public void handle(OrderContext ctx) {
        System.out.println("订单已支付 -> 执行发货逻辑...");
        ctx.setState(new ShippedState());
    }
}

class ShippedState implements State {
    public void handle(OrderContext ctx) {
        System.out.println("订单已发货 -> 执行收货逻辑...");
        ctx.setState(new DoneState());
    }
}

class DoneState implements State {
    public void handle(OrderContext ctx) {
        System.out.println("订单已完成");
    }
}

class OrderContext {
    private State state;
    public OrderContext(State state) {
        this.state = state;
    }
    public void setState(State state) {
        this.state = state;
    }
    public void process() {
        state.handle(this);
    }
}

驱动代码:用集合 + 循环执行

public class TestOrder {
    public static void main(String[] args) {
        OrderContext order = new OrderContext(new UnpaidState());

        // 一直循环直到状态是 DoneState
        while (!(order.state instanceof DoneState)) {
            order.process();
        }
        // 最后一遍处理完成状态
        order.process();
    }
}

特点

  • 不用写多行 request(),直接用循环驱动
  • 如果状态机变长/变短,不影响调用逻辑
  • 也可以设计一个 List 状态链 提前加载好,遍历一次性跑完

3、ArrayList 配置“状态流”

状态模式也可以结合 状态数组

List<State> flow = List.of(
    new UnpaidState(),
    new PaidState(),
    new ShippedState(),
    new DoneState()
);

OrderContext ctx = new OrderContext(flow.get(0));
for (State state : flow) {
    ctx.setState(state);
    ctx.process();
}
  • 优势:业务状态流程可以从配置文件甚至数据库加载,不用改代码
  • 实现可拥抱灵活性,比如读取“审批流”、“工单流”这些可配置流程


3、总结

如下所示:


总结

        状态模式是一种行为型设计模式,允许对象在内部状态改变时改变其行为。模式中包含上下文抽象状态具体状态角色。

        优点包括解耦客户端和状态对象,可扩展性强,避免大量条件语句。缺点是可能增加系统类的数量和复杂性。适用场景如自动售货机的状态转换、线程状态管理等。


参考文章:

1、设计模式第21讲——状态模式(State)-CSDN博客文章浏览阅读6.7k次,点赞22次,收藏104次。状态模式是一种行为型设计模式,允许对象在内部状态改变时改变其行为。模式中包含上下文、抽象状态和具体状态角色。优点包括解耦客户端和状态对象,可扩展性强,避免大量条件语句。缺点是可能增加系统类的数量和复杂性。适用场景如自动售货机的状态转换、线程状态管理等。代码示例展示了自动售卖机如何利用状态模式实现不同状态的切换。 https://blog.csdn.net/weixin_45433817/article/details/131521862?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522d157caaef17e4af5a1ebe4b41acb1286%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=d157caaef17e4af5a1ebe4b41acb1286&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~top_positive~default-1-131521862-null-null.142^v102^control&utm_term=%E7%8A%B6%E6%80%81%E6%A8%A1%E5%BC%8F&spm=1018.2226.3001.4187


网站公告

今日签到

点亮在社区的每一天
去签到