2

设计模式之状态模式 - 程序员田同学

 1 year ago
source link: https://www.cnblogs.com/tianClassmate/p/16733554.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

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

一、概念理解

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

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

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

环境类(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 等冗余语句,代码更有层次性,并且具备良好的扩展力。

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

设计模式的学习要成体系,推荐你看我往期发布的设计模式文章。

一、设计模式概述

二、设计模式之工厂方法和抽象工厂

三、设计模式之单例和原型

四、设计模式之建造者模式

五、设计模式之代理模式

六、设计模式之适配器模式

七、设计模式之桥接模式

八、设计模式之组合模式

九、设计模式之装饰器模式

十、设计模式之外观模式

十一、外观模式之享元模式

十二、设计模式之责任链模式

十三、设计模式之命令模式

十四、设计模式之解释器模式

十五、设计模式之迭代器模式

十六、设计模式之中介者模式

十七、设计模式之备忘录模式

十八、设计模式之观察者模式


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK