23种设计模式--状态模式

状态模式

  • 一、基本概念
  • 二、主要思想
  • 三、使用场景
  • 四、应用实例
  • 五、拓展

一、基本概念

在软件开发过程中,应用程序中的部分对象可能会根据不同的情况做出不同的行为,我们把这种对象称为有状态的对象,而把影响对象行为的一个或多个动态变化的属性称为状态
当有状态的对象与外部事件产生互动时,其内部状态就会发生改变,从而使其行为也发生改变。

对这种有状态的对象编程,传统的解决方案是:将这些所有可能发生的情况全都考虑到,然后使用 if-else 或 switch-case 语句来做状态判断,再进行不同情况的处理。
但是显然这种做法对复杂的状态判断存在天然弊端,条件判断语句会过于臃肿,可读性差,且不具备扩展性,维护难度也大。且增加新的状态时要添加新的 if-else 语句,这违背了“开闭原则”,不利于程序的扩展。

二、主要思想

以上问题如果采用“状态模式”就能很好地得到解决。状态模式的解决思想是:当控制一个对象状态转换的条件表达式过于复杂时,把相关“判断逻辑”提取出来,用各个不同的类进行表示,系统处于哪种情况,直接使用相应的状态类对象进行处理,这样能把原来复杂的逻辑判断简单化,消除了 if-else、switch-case 等冗余语句,代码更有层次性,并且具备良好的扩展力。

优点:

  1. 结构清晰,状态模式将与特定状态相关的行为局部化到一个状态中,并且将不同状态的行为分割开来,满足“单一职责原则”。
  2. 将状态转换显示化,减少对象间的相互依赖。将不同的状态引入独立的对象中会使得状态转换变得更加明确,且减少对象间的相互依赖。
  3. 状态类职责明确,有利于程序的扩展。通过定义新的子类很容易地增加新的状态和转换。

缺点:

  1. 状态模式的使用必然会增加系统的类与对象的个数。
  2. 状态模式的结构与实现都较为复杂,如果使用不当会导致程序结构和代码的混乱。
  3. 状态模式对开闭原则的支持并不太好,对于可以切换状态的状态模式,增加新的状态类需要修改那些负责状态转换的源码,否则无法切换到新增状态,而且修改某个状态类的行为也需要修改对应类的源码。

一句话总结
把判断对象状态的复杂“判断逻辑”提取到子类中,允许子类在其内部状态发生改变时改变其行为。

三、使用场景

23种设计模式--状态模式_第1张图片

订单的状态有很多种,有待支付、待发货等等,而且每种状态下的订单处理逻辑也比较多,在这个过程中如果使用硬编码,我们就需要一系列的 if-else 语句来检查订单的当前状态、可执行操作以及这两个组合得到的下一个应该被流转的状态值。如果订单的状态流转很复杂,代码逻辑就会很复杂,可拓展性弱,可读性低,后期维护困难。

对于这种情况,我们可以使用状态机模式来处理。

四、应用实例

23种设计模式--状态模式_第2张图片

上面是状态的模式的雷图,主要包含三种角色:

  1. 订单环境类(OrderContext)角色:
    也称为上下文,它定义了客户端需要的接口,内部维护一个当前状态,并负责具体状态的切换。
  2. 抽象状态(OrderState)角色:
    定义一个接口,用以封装环境对象中的特定状态所对应的行为,可以有一个或多个行为。
  3. 具体状态(WaitPay、WaitRecv、WaitSend、WaitValuate、Finished)角色:
    实现抽象状态所对应的行为,并且在需要的情况下进行状态切换。

OrderContext代码实现如下:

/**
 * @Author dingws
 * @PackageName JavaStudy
 * @Package org.goodStudy.designPattern.stateMode
 * @Date 2021/11/8 4:10 下午
 * @Version 1.0
 */
public class OrderContext {
    State state = State.WAIT_PAY;

    OrderState orderState = new WaitPay();

    public void OrderContext(){
        orderState = new WaitPay();
    }

    public void Handle(){
        orderState.Handle(this);
    }

    public State getState() {
        return state;
    }

    public void setState(State state) {
        this.state = state;
    }

    public OrderState getOrderState(){
        return this.orderState;
    }

    public void setOrderState(OrderState orderState) {
        this.orderState = orderState;
    }

    /**
     * main函数
     * @param args
     */
    public static void main(String[] args) {
        OrderContext orderContext = new OrderContext();
        orderContext.Handle();
        orderContext.Handle();
        orderContext.Handle();
        orderContext.Handle();
        orderContext.Handle();
    }
}

OrderState的代码实现如下:

/**
 * @Author dingws
 * @PackageName JavaStudy
 * @Package org.goodStudy.designPattern.stateMode
 * @Date 2021/11/2 2:15 下午
 * @Version 1.0
 */
public abstract class OrderState {
    public abstract void Handle(OrderContext orderContext);
}

WaitPay、WaitRecv、WaitSend、WaitValuate、Finished 的代码实现如下:

/**
 * @Author dingws
 * @PackageName JavaStudy
 * @Package org.goodStudy.designPattern.stateMode
 * @Date 2021/11/2 2:15 下午
 * @Version 1.0
 */
class WaitPay extends OrderState {

    @Override
    public void Handle(OrderContext orderContext) {
        if (orderContext.getState() == State.WAIT_PAY){
            System.out.println("用户已付款,等待发货");
            orderContext.setState(State.WAIT_SEND);
            orderContext.setOrderState(new WaitSend());
        } else {
            System.out.println("等待用户支付,当前订单状态为:" + orderContext.getState().getName());
        }
    }
}

class WaitSend extends OrderState {

    @Override
    public void Handle(OrderContext orderContext){
        if (orderContext.getState() == State.WAIT_SEND){
            System.out.println("卖家已发货,等待订单签收");
            orderContext.setState(State.WAIT_RECV);
            orderContext.setOrderState(new WaitRecv());
        } else {
            System.out.println("等待卖家发货,当前订单状态为:" + orderContext.getState().getName());
        }
    }
}

class WaitRecv extends OrderState {

    @Override
    public void Handle(OrderContext orderContext){
        if (orderContext.getState() == State.WAIT_RECV){
            System.out.println("订单已签收,等待用户评价");
            orderContext.setState(State.WAIT_VALUATE);
            orderContext.setOrderState(new WaitValuate());
        } else {
            System.out.println("等待用户签收订单,当前订单状态为:" + orderContext.getState().getName());
        }
    }
}

class WaitValuate extends OrderState {

    @Override
    public void Handle(OrderContext orderContext){
        if (orderContext.getState() == State.WAIT_VALUATE){
            System.out.println("用户已评价,订单关闭");
            orderContext.setState(State.FINISHED);
            orderContext.setOrderState(new Finished());
        } else {
            System.out.println("等待卖家发货,当前订单状态为:" + orderContext.getState().getName());
        }
    }
}

class Finished extends OrderState{

    @Override
    public void Handle(OrderContext orderContext){
        if (orderContext.getState() == State.FINISHED){
            System.out.println("订单已完成");
        } else {
            System.out.println("等待订单完成,当前订单状态为:" + orderContext.getState().getName());
        }
    }
}

State枚举类的实现代码如下:

/**
 * @Author dingws
 * @PackageName JavaStudy
 * @Package org.goodStudy.designPattern.stateMode
 * @Date 2021/11/2 2:07 下午
 * @Version 1.0
 */
public enum State {
    WAIT_PAY(1, "待付款"),
    WAIT_SEND(2, "待发货"),
    WAIT_RECV(3, "待签收"),
    WAIT_VALUATE(4, "待评价"),
    FINISHED(5, "订单已完成");

    private final int id;
    private final String name;

    State(int id, String name){
        this.id = id;
        this.name = name;
    }

    State(State state){
        this.id = state.id;
        this.name = state.name;
    }

    public int getId() {
        return id;
    }

    public String getName() {
        return name;
    }
}

运行结果如下:

23种设计模式--状态模式_第3张图片

五、拓展

以上就是状态机的详细讲解了,在运行后,我发现一个问题,各个具体状态之间(WaitPay、WaitRecv、WaitSend、WaitValuate、Finished),需要依赖自己要状态跳转的类,这样耦合度就增加了,有没有更好的办法呢?

于是,我在上面的版本上,又优化了一版。

23种设计模式--状态模式_第4张图片

相较于上个版本,此版本仅增加了一个Active枚举类,在各个状态类中,仅需要关注触发的条件和跳转到的恶状态即可,不需要知道别的具体处理类,更大限度的减少了耦合性。

Active状态实现:

/**
 * @Author dingws
 * @PackageName JavaStudy
 * @Package org.goodStudy.designPattern.stateMode
 * @Date 2021/11/2 2:24 下午
 * @Version 1.0
 */
public enum Active {
    ACTIVE_PAY(1, "付款"),
    ACTIVE_SEND(2, "发货"),
    ACTIVE_RECV(3, "签收"),
    ACTIVE_VALUATE(4, "评价"),
    ACTIVE_CACLE(5, "取消");

    private final int id;
    private final String name;


    Active(int id, String name) {
        this.id = id;
        this.name = name;
    }

    public int getId() {
        return id;
    }

    public String getName() {
        return name;
    }
}

OrderContext实现

/**
 * @Author dingws
 * @PackageName JavaStudy
 * @Package org.goodStudy.designPattern.stateMode
 * @Date 2021/11/8 4:10 下午
 * @Version 1.0
 */
public class OrderContext {
    OrderState orderState;

    public void OrderContext(){
        orderState = new WaitPay();
    }

    public void Handle(Active active){
        orderState.Handle(active);
    }

    public void setOrderState(OrderState orderState) {
        this.orderState = orderState;
    }

    public static void main(String[] args) {
        OrderContext orderContext = new OrderContext();
        orderContext.setOrderState(new WaitPay());
        orderContext.Handle(Active.ACTIVE_PAY);

        System.out.println("-------");
        orderContext.Handle(Active.ACTIVE_VALUATE);
        System.out.println("-------");

        orderContext.setOrderState(new WaitSend());
        orderContext.Handle(Active.ACTIVE_SEND);
        orderContext.setOrderState(new WaitRecv());
        orderContext.Handle(Active.ACTIVE_RECV);
        orderContext.setOrderState(new WaitValuate());
        orderContext.Handle(Active.ACTIVE_VALUATE);
        orderContext.setOrderState(new Finished());
        orderContext.Handle(Active.ACTIVE_VALUATE);
    }
}

OrderState实现:

/**
 * @Author dingws
 * @PackageName JavaStudy
 * @Package org.goodStudy.designPattern.stateMode
 * @Date 2021/11/2 2:15 下午
 * @Version 1.0
 */
public class OrderState {
    protected State state = State.FINISHED;

    void OrderState(){
        state = State.FINISHED;
    }

    public void Handle(Active active){

    }
}

class WaitPay extends OrderState {

    @Override
    public void Handle(Active active){
        if (active == Active.ACTIVE_PAY){
            System.out.println("用户已付款,等待发货");
            this.state = State.WAIT_SEND;
        } else if (active == Active.ACTIVE_CACLE) {
            this.state = State.FINISHED;
        } else {
            System.out.println("等待用户支付,当前订单状态为:" + state.getName());
        }
    }
}

class WaitSend extends OrderState {

    @Override
    public void Handle(Active active){
        if (active == Active.ACTIVE_SEND){
            System.out.println("卖家已发货,等待订单签收");
            this.state = State.WAIT_RECV;
        } else {
            System.out.println("等待卖家发货,当前订单状态为:" + state.getName());
        }
    }
}

class WaitRecv extends OrderState {

    @Override
    public void Handle(Active active){
        if (active == Active.ACTIVE_RECV){
            System.out.println("订单已签收,等待用户评价");
            this.state = State.WAIT_VALUATE;
        } else if (active == Active.ACTIVE_CACLE) {
            if (state == State.WAIT_SEND){
                System.out.println("商品未发货,取消订单成功");
                this.state = State.FINISHED;
            } else {
                System.out.println("商品未发货,取消订单失败");
            }
        }  else {
            System.out.println("等待用户签收订单,当前订单状态为:" + state.getName());
        }
    }
}

class WaitValuate extends OrderState {

    @Override
    public void Handle(Active active){
        if (active == Active.ACTIVE_VALUATE){
            System.out.println("用户已评价,订单关闭");
            this.state = State.FINISHED;
        } else {
            System.out.println("等待卖家发货,当前订单状态为:" + state.getName());
        }
    }
}

class Finished extends OrderState{

    @Override
    public void Handle(Active active){
        if (state == State.FINISHED){
            System.out.println("订单已完成");
        } else {
            System.out.println("等待订单完成,当前订单状态为:" + state.getName());
        }
    }
}

参考链接:
https://blog.csdn.net/qq_33000453/article/details/106749593
http://c.biancheng.net/view/1388.html
http://c.biancheng.net/view/8492.html

你可能感兴趣的:(java,程序员内功--设计模式,状态模式,设计模式)