设计模式-状态模式

目录

一、概念理解

二、案例实现

抽象状态:

具体状态-订单付款:

具体状态-订单发货

具体状态-订单确认收货

环境类:

客户端调用:

三、总结


   实际开发中订单往往都包含着订单状态,用户每进行一次操作都要切换对应的状态,而每次切换判断当前的状态是必须的,就不可避免的引入一系列判断语句,为了让代码更加清晰直观,我们引入今天的主角——状态模式。

一、概念理解

   

状态模式是指,一个对象在其内部状态发生改变时会改变它的行为;

状态模式又称为状态机,有多种:

  •      有限状态机(FSM)
  •      并发状态机
  •       分层状态机
  •       下推(栈)状态机

状态机是一个非常棒的设计,值得花大心思去好好学。平常用的动画状态机、AI行为树都是状态机的应用。

简单套路模板:(这里只是简单概况)

1. State 抽象状态类 

2. ConcreteState 具体状态类 

3. StateManger 状态管理类 ,用于改变状态

   假设订单状态有,下单、发货、确认收货,如果用户确认收货,在常规编程中就要判断当前用户的状态,然后再修改状态,如果这种情况下使用状态模式。

    将各个状态都抽象成一个状态类,比如下单状态类、发货状态类、确认收货类,在状态类中处理相应的逻辑和控制下一个状态,在定义一个环境类,定义初始状态,并控制切换状态。

在状态模式中应该包含着三个角色:

       环境类(Context)角色:也称为上下文,它定义了客户端需要的接口,内部维护一个当前状态,这个类持有State接口,负责保持并切换当前的状态。

       抽象状态(State)角色:定义一个接口,用以封装环境对象中的特定状态所对应的行为,可以有一个或多个行为。

       具体状态(Concrete State)角色:实现抽象状态所对应的行为,并且在需要的情况下进行状态切换。

      以下为状态模式的类图,看起来是很直观的,理解起来也简单,我们需要说明的是状态模式的类图和策略模式的类图长的一样,但写起来状态模式比策略模式要难。

image-20220926090555866

      我们要注意这段话,在状态模式中,类的行为是基于它的状态改变的,状态之间的切换,在状态A执行完毕后自己控制状态指向状态B,状态模式是不停的切换状态执行。这也是状态模式和策略模式不一样的地方。

    另外在状态模式中,状态A到B是由自己控制的,而不是由客户端来控制,这是状态模式和策略模式最显著的特征。

    我们基于订单状态案例实现demo。

二、案例实现

抽象状态:

定义统一的状态切换方法

/**
 * 抽象状态
 * @author tcy
 * @Date 20-09-2022
 */
public abstract class OrderStateAbstract {
    protected Context context;

    public void setContext(Context context) {
        this.context = context;
    }
        /**
         * 状态切换
         */
    public abstract void handle();

}

具体状态-订单付款:

实现状态接口,处理相应的逻辑,并定义下一个状态

/**
 * 订单付款
 * @author tcy
 * @Date 21-09-2022
 */
public class OrderStatePay extends OrderStateAbstract {
   @Override
    public void handle() {
        System.out.println("订单已支付,执行下个状态...");
        context.changeState(new OrderStateOut());

    }
}

具体状态-订单发货

/**
 * 订单发货
 * @author tcy
 * @Date 21-09-2022
 */
public class OrderStateOut extends OrderStateAbstract {
     @Override
    public void handle() {
        System.out.println("订单已经发货,开始下一状态...");
        context.changeState(new OrderStateSubmit());
    }
}

具体状态-订单确认收货

/**
 * 订单提交
 * @author tcy
 * @Date 21-09-2022
 */
public class OrderStateSubmit extends OrderStateAbstract {
    @Override
    public void handle() {
        System.out.println("订单已经确认收货...");
    }
}

环境类:

持有最新状态,并调用具体的状态切换方法

/**
 * 环境类
 * @author tcy
 * @Date 20-09-2022
 */
public class Context {

   private OrderStateAbstract state;

    //定义环境类的初始状态
    public Context() {
        this.state = new OrderStatePay();
        state.setContext(this);
    }

	//状态切换
    public void changeState(OrderStateAbstract state) {
        this.state = state;
        this.state.setContext(this);
    }


    /**
     * 审批通过请求
     */
    public void request() {
        this.state.handle();
    }
}

客户端调用:

/**
 * @author tcy
 * @Date 20-09-2022
 */
public class Client {
    public static void main(String[] args) {

         //创建环境
        Context context = new Context();
        //订单付款
        context.request();
        //订单发货
        context.request();
        //订单付款
        context.request();

    }
}

状态模式客户端调用比较简单,由状态内部类进行状态切换。

三、总结

    在实际开发中,当控制一个对象状态转换的条件表达式过于复杂时,就可以使用状态模式把相关“判断逻辑”提取出来,用各个不同的类进行表示。

    系统处于哪种情况,直接使用相应的状态类对象进行处理,这样能把原来复杂的逻辑判断简单化,消除了 if-else、switch-case 等冗余语句,代码更有层次性,并且具备良好的扩展力。

     比如审批流程,我们案例也仅仅是用于订单流程做例子,在实际开发中并不会使用这种方式处理订单,因为订单的处理逻辑实际上并不是那么复杂,引入状态模式反而增加了更多的类,造成系统更加的复杂,这也是设计模式最显著的缺点。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 11
    评论
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Upaaui

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

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

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

打赏作者

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

抵扣说明:

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

余额充值