状态模式——状态转换的优化神器

本文详细介绍了状态模式的概念,通过电梯门和物流状态切换的例子展示了如何使用状态模式来管理和切换对象的行为。同时讨论了状态模式与策略模式的相似之处以及其在复杂状态管理中的优势。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

状态模式(State Pattern)是一种行为型设计模式,它允许对象在其内部状态发生变化时改变其行为。状态模式的核心思想是将对象的状态封装成不同的类,并在对象内部维护一个指向当前状态的引用。这使得对象在不同状态下具有不同的行为,而且可以在运行时动态切换状态。其实这有点像策略模式,共同点都是是传入的状态|策略对象来驱动行为。下面给出例子并说明使用状态模式和不使用状态模式实现状态转换功能的区别。

状态模式实现状态转换

我们就使用电梯门的开关为例子讲解状态模式,假设我们传入一个关门的状态参数电梯门就立即关上,传入一个开门的状态参数电梯门就立即打开。那么状态模式的实现方式如下:

// 1. State 接口
interface State {
    void handle(Context context);
}

// 2. 实现具体开关门状态
class OpenState implements State {
    @Override
    public void handle(Context context) {
        System.out.println("电梯门已打开");
        // 调用底层接口开门,其他处理...
    }
}

class CloseState implements State {
    @Override
    public void handle(Context context) {
        System.out.println("电梯门已关闭");
        //调用底层接口关门, 其他处理...
    }
}

// 3. Context 状态上下文,维护状态引用
// 作用就是接受状态参数切换状态,并可以调用该状态下的行为
class Context {
    private State currentState;
    public void setState(State state) {
        this.currentState = state;
    }
    public void request() {
        currentState.handle(this);
    }
}

public class StateModelDemo {
    // 4. 测试状态切换
    public static void main(String[] args) {
        Context context = new Context();

        State openState = new OpenState();
        State closeState = new CloseState();

        context.setState(openState);
        context.request(); // 输出:电梯门已打开

        context.setState(closeState);
        context.request(); // 输出:电梯门已关闭
    }
}

物流状态切换例子

假设有个需求是有个物流状态的切换,状态分为四种分别是:未收件、已收件、运输中、已签收四种状态,并且状态是单向无环不可逆的。我们使用状态模式和不使用状态模式的区别就是不用写大量的 if else 循环,下面演示两种实现方式:

传统写法

传统写法很简单,但是每到进行状态转换的地方就需要做无数的判断,如下所示:

class Order{
    private Long id; 
    private String state; 
    public Order(){
        this.state = "UNRECEIVED";
    }
    public void setState(String state){
        this.state = state;
    }
    public String getState(){
        return this.state;
    }
}

public class OneWayState {
    public static void main(String[] args) {
        Order order = new Order();
        // 获取当前订单状态
        String state = order.getState();
        System.out.println(order.getState());
        // 订单状态转换
        if (state.equals("UNRECEIVED")) {
            order.setState("RECEIVED");
        } else if (state.equals("RECEIVED")) {
            order.setState("TRANSPORTING");
        } else if (state.equals("TRANSPORTING")) {
            order.setState("FINISHED");
        } else if (state.equals("FINISHED")) {
            order.setState(null);
        }
        System.out.println(order.getState());
    }
}
使用状态模式状态转换的代码优化

首先我们定义一个订单状态的接口,将状态抽离出来,如下:

public interface OrderState {
    public void nextState(Order order);
}

接着我们就要实现四种不同的订单状态,我们需要写四个状态实现类实现上面的OrderState接口,这样太烦了,不如直接定义成一个枚举类实现OrderState接口,如下所示,在枚举类中我们定义了上述接口的实现方法:

public enum OrderStateEnum implements OrderState{
    // 状态分为四种分别是:未收件、已收件、运输中、已签收
    // 未收件
    UNRECEIVED{
        @Override
        public void nextState(Order order) {
            order.setState(RECEIVED);
        }
    },
    // 已收件
    RECEIVED{
        @Override
        public void nextState(Order order) {
            order.setState(TRANSPORTING);
        }
    },
    // 运输中
    TRANSPORTING{
        @Override
        public void nextState(Order order) {
            order.setState(FINISHED);
        }
    },
    // 已签收
    FINISHED{
        @Override
        public void nextState(Order order) {
            order.setState(null);
        }
    },
}

最后编写我们的订单类Order类,如下:

public class Order {
    private Long id; 
    private OrderStateEnum state;
    public Order(){
        this.state = OrderStateEnum.UNRECEIVED;
    }
    public void nextState(){
        this.state.nextState(this);
    } 
    public void setState(OrderStateEnum state){
        this.state = state;
    }
    public OrderStateEnum getState(){
        return this.state;
    } 
}

最后在测试类中我们可以通过简单调用nextState()即可进行状态转换,如下所示:

public class Main {
    public static void main(String[] args) {
        Order order = new Order();
        System.out.println(order.getState());
        order.nextState();
        System.out.println(order.getState());
        order.nextState();
        System.out.println(order.getState());
        order.nextState();
        System.out.println(order.getState());
    }
}

打印结果如下:

UNRECEIVED
RECEIVED
TRANSPORTING
FINISHED

以后在所有的业务中,你仅仅需要调用order.getState()即可将当前的订单状态切换到下一个状态,避免每一次都写大量的 if else等逻辑,代码非常具有可维护性,如果以后要新加状态或者改状态名,只需要在状态枚举类中修改即可,改一处即可,如果if else的方法则需要到处修改。这就是设计模式的魅力!!!!! 设计模式YYDS!听懂,掌声!

如果具有分叉或者环的状态如何实现?

如果是类似下面线程生命周期的状态,具有环和分叉的状态转换,如何使用状态设计模式实现呢?其实都是一样的,只不过判断条件多一点而已。在枚举实现类中的不是简单地调用nextState()方法,而是需要传入一个参数表示方向,从而判断状态的变化。
在这里插入图片描述
如下仅给出运行状态的部分判断逻辑的实现,如果逻辑较为复杂可以不使用枚举类:

//具体状态类:运行状态
class Running extends ThreadState {
    public Running() {
        stateName = "运行状态";
        System.out.println("当前线程处于:运行状态.");
    }
    public void suspend(ThreadContext hj) {
        System.out.print("调用suspend()方法-->");
        if (stateName.equals("运行状态")) {
            hj.setState(new Blocked());
        } else {
            System.out.println("当前线程不是运行状态,不能调用suspend()方法.");
        }
    }
    public void stop(ThreadContext hj) {
        System.out.print("调用stop()方法-->");
        if (stateName.equals("运行状态")) {
            hj.setState(new Dead());
        } else {
            System.out.println("当前线程不是运行状态,不能调用stop()方法.");
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

矩阵科学

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值