设计模式之状态模式

状态模式是一种行为设计模式,用于当对象的行为取决于其状态时。本文通过京东物流的例子,阐述了如何定义状态接口、物流Context类以及各种具体状态类,并讨论了状态模式的优势和适用场景,有助于减少代码中的条件语句并提高可扩展性。
摘要由CSDN通过智能技术生成

一句话总结

在其位 谋其政

个人感觉这个总结不是太好 但是脑子第一反应就是这句话 就用他来解释吧

- 在其位

在其位说明是坐在这个位置上 (达到某个状态) 说明类里面有个对象是记录状态的(还是个抽象类)
位置不止一个状态也不止一个 (抽象类的子类不止一个)
当状态增加的时候 对应的实现类也增加

  • 谋其政

只有我拥有某个权力后才会干相应的事 (类的行为是基于它的状态改变的)
达到某个状态才调用对应的方法 (方法可能不止一个)

这样理解可以很简单的分析出状态模式的3个角色

  • State :(规范我的行为)是一个接口,封装了状态及其行为

  • ConcreteState X:(不同状态的我) State的实现类,表示具体的状态(不同的状态重写不同的方法)

  • Context :(善变的我) 保持并切换各个状态,其持有一个State的引用。它将依赖状态的各种操作委托给不同的状态对象执行。其负责与客户端交互
    UML类图
    在这里插入图片描述

状态模式之京东物流

双十一女朋友送了个固态硬盘 自从下单以来,我看物流状态信息,心心念念着自己的固态硬盘快点到…

这个物流系统就很适合使用状态模式来开发,因为此过程存在很多不同的状态,例如接单,出库,运输,送货,收货,评价等等。而订单在每个不同的状态下的操作可能都不一样,例如在接单状态下,商家就需要通知仓库拣货,通知用户等等操作,其他状态类似

下面是实例的UML类图
在这里插入图片描述

第一,定义一个状态接口

此接口定义各个状态的统一操作接口

public interface LogisticsState {
    void doAction(JdLogistics context);
}

第二,定义一个物流Context类

此类持有一个LogisticsState 的引用,负责在流程中保持并切换状态

public class JdLogistics {
    private LogisticsState logisticsState;

    public void setLogisticsState(LogisticsState logisticsState) {
        this.logisticsState = logisticsState;
    }

    public LogisticsState getLogisticsState() {
        return logisticsState;
    }

    public void doAction(){
        Objects.requireNonNull(logisticsState);
        logisticsState.doAction(this);
    }
}

第三,实现各种状态类

接单状态类,其需要实现LogisticsState接口

    //接单状态
public class OrderState implements LogisticsState {
@Override
public void doAction(JdLogistics context) {
    System.out.println("商家已经接单,正在处理中...");
}
}
//出库状态类

public class ProductOutState implements LogisticsState {
@Override
public void doAction(JdLogistics context) {
    System.out.println("商品已经出库...");
}
}
//运输状态
public class TransportState  implements LogisticsState {
    @Override
    public void doAction(JdLogistics context) {
        System.out.println("商品正在运往河南分发中心");
    }
}

依次类推,可以建立任意多个状态类

第四, 客户端使用

public class StateClient {
    public static void main(String[] args) {

        //状态的保持与切换者
        JdLogistics jdLogistics = new JdLogistics();


        /**
         * 客户下单商家接单时调用相关接口把接单状态赋值
         */
        //接单状态
        OrderState orderState = new OrderState();
        jdLogistics.setLogisticsState(orderState);
        jdLogistics.doAction();

        /**
         * 当快递小哥扫描订单后 调用相关接口 状态赋值为出库
         */
        //出库状态
        ProductOutState productOutState = new ProductOutState();
        jdLogistics.setLogisticsState(productOutState);
        jdLogistics.doAction();
        /**
         * 当快递车发车后 调用接口 状态赋值为出库
         */
        //运输状态
        TransportState transportState = new TransportState();
        jdLogistics.setLogisticsState(transportState);
        jdLogistics.doAction();
    }
}

输出结果:

商家已经接单,正在处理中...
商品已经出库...
商品正在运往河南分发中心

可见,我们将每个状态下要做的具体动作封装到了每个状态类中,我们只需要切换不同的状态即可。如果不使用状态模式,我们的代码中可能会出现很长的if else列表,这样就不便于扩展和修改了。

以下来之菜鸟教程

介绍

意图:允许对象在内部状态发生改变时改变它的行为,对象看起来好像修改了它的类。

主要解决:对象的行为依赖于它的状态(属性),并且可以根据它的状态改变而改变它的相关行为。

何时使用:代码中包含大量与对象状态有关的条件语句。

如何解决:将各种具体的状态类抽象出来。

关键代码:通常命令模式的接口中只有一个方法。而状态模式的接口中有一个或者多个方法。而且,状态模式的实现类的方法,一般返回值,或者是改变实例变量的值。也就是说,状态模式一般和对象的状态有关。实现类的方法有不同的功能,覆盖接口中的方法。状态模式和命令模式一样,也可以用于消除 if…else 等条件选择语句。

应用实例: 1、打篮球的时候运动员可以有正常状态、不正常状态和超常状态。 2、曾侯乙编钟中,‘钟是抽象接口’,'钟A’等是具体状态,'曾侯乙编钟’是具体环境(Context)。

优点: 1、封装了转换规则。 2、枚举可能的状态,在枚举状态之前需要确定状态种类。 3、将所有与某个状态有关的行为放到一个类中,并且可以方便地增加新的状态,只需要改变对象状态即可改变对象的行为。 4、允许状态转换逻辑与状态对象合成一体,而不是某一个巨大的条件语句块。 5、可以让多个环境对象共享一个状态对象,从而减少系统中对象的个数。

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

使用场景: 1、行为随状态改变而改变的场景。 2、条件、分支语句的代替者。

注意事项:在行为受状态约束的时候使用状态模式,而且状态不超过 5 个。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

一叶一菩提魁

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

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

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

打赏作者

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

抵扣说明:

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

余额充值