23种设计模式(七)-状态设计模式 (下)

简介: 23种设计模式(七)-状态设计模式 (下)

第二种: 带有取消付款和退货退款状态。


退货退款最开始只能是收到货以后才能退。

5f3d79cd665d4125b0f631a9e8d8008b_tplv-k3u1fbpfcp-zoom-1.png这种方式和第一个有所不同, 待付款和确认收货不止有一个状态流转,当有多个状态流转,甚至是更多的状态是,我们应该如何处理呢?


第一步: 定义上下文环境类。


这里环境上下文定义了所有的状态方法。

package com.lxl.www.designPatterns.statePattern.order2;
/**
 * 订单上下文
 */
public class OrderContext {
    /**在上下文类中记录订单状态*/
    private IOrderStatus orderStatus;
    public OrderContext() {
        System.out.println("开始购物");
        // 最开始是待付款状态
        this.orderStatus = new Pending();
    }
    public void setOrderStatus(IOrderStatus orderStatus) {
        this.orderStatus = orderStatus;
    }
    /**
     * 付款完成
     */
    public void pending() {
        this.orderStatus.pending(this);
    }
    public void waitOut() {
        this.orderStatus.waitOut(this);
    }
    public void waitReceive() {
        this.orderStatus.waitReceive(this);
    }
    public void confirmReceived() {
        this.orderStatus.confirmReceived(this);
    }
    public void orderEvaluation() {
        this.orderStatus.orderEvaluation(this);
    }
    public void finish() {
        this.orderStatus.finish(this);
    }
    public void cancelPay() {
        this.orderStatus.cancelPay(this);
    }
    public void refunds() {
        this.orderStatus.refunds(this);
    }
}

第二步:定义抽象状态类

package com.lxl.www.designPatterns.statePattern.order2;
/**
 * 订单状态
 */
public interface IOrderStatus {
    /*
     * 待付款
     */
    void pending(OrderContext context);
    /*
     * 取消付款
     */
    void cancelPay(OrderContext context);
    /*
     * 待出库
     */
    void waitOut(OrderContext context);
    /*
     * 退货退款
     */
    void refunds(OrderContext context);
    /*
     * 待收货
     */
    void waitReceive(OrderContext context);
    /*
     * 确认收货
     */
    void confirmReceived(OrderContext context);
    /*
     * 订单评价
     */
    void orderEvaluation(OrderContext context);
    /*
     * 订单完成
     */
    void finish(OrderContext context);
}

第三步:定义具体状态类。


我们这里定义了待付款,待出库,待收货, 确认收货,订单评价,订单完成,取消付款,退货退款一共8个状态。


待付款

package com.lxl.www.designPatterns.statePattern.order2;
/**
 * 待付款
 */
public class Pending implements IOrderStatus {
    public Pending() {
        System.out.println("当前状态::待付款");
    }
    @Override
    public void pending(OrderContext context) {
        System.out.println("付款完成了, 待出库");
        context.setOrderStatus(new WaitOut());
    }
    /*
     * 取消付款
     */
    public void cancelPay(OrderContext context) {
        System.out.println("取消付款");
        context.setOrderStatus(new Finish());
    }
    @Override
    public void waitOut(OrderContext context) {
        System.out.println("去付款-->付款完成,待出库");
        context.setOrderStatus(new WaitOut());
    }
    /*
     * 退货退款
     */
    public void refunds(OrderContext context) {
    }
    @Override
    public void waitReceive(OrderContext context) {
    }
    @Override
    public void confirmReceived(OrderContext context) {
    }
    @Override
    public void orderEvaluation(OrderContext context) {
    }
    @Override
    public void finish(OrderContext context) {
    }
}

待出库

package com.lxl.www.designPatterns.statePattern.order2;
/**
 * 待出库
 */
public class WaitOut implements IOrderStatus {
    public WaitOut() {
        System.out.println("当前状态::待出库");
    }
    @Override
    public void pending(OrderContext context) {
    }
    @Override
    public void cancelPay(OrderContext context) {
    }
    /*
     * 退货退款
     */
    public void refunds(OrderContext context) {
        System.out.println("申请退货");
        context.setOrderStatus(new Refunds());
    }
    @Override
    public void waitOut(OrderContext context) {
        System.out.println("出库完成, 待收货");
        context.setOrderStatus(new WaitReceive());
    }
    @Override
    public void waitReceive(OrderContext context) {
    }
    @Override
    public void confirmReceived(OrderContext context) {
    }
    @Override
    public void orderEvaluation(OrderContext context) {
    }
    @Override
    public void finish(OrderContext context) {
    }
}

待收货

package com.lxl.www.designPatterns.statePattern.order2;
/**
 * 待收货
 */
public class WaitReceive implements IOrderStatus {
    public WaitReceive() {
        System.out.println("当前状态 :: 待收货");
    }
    @Override
    public void pending(OrderContext context) {
    }
    @Override
    public void cancelPay(OrderContext context) {
    }
    @Override
    public void waitOut(OrderContext context) {
    }
    /*
     * 退货退款
     */
    public void refunds(OrderContext context) {
        System.out.println("申请退货");
        context.setOrderStatus(new Refunds());
    }
    @Override
    public void waitReceive(OrderContext context) {
        System.out.println("进行收货, 完成收货动作");
        context.setOrderStatus(new Confirm());
    }
    @Override
    public void confirmReceived(OrderContext context) {
    }
    @Override
    public void orderEvaluation(OrderContext context) {
    }
    @Override
    public void finish(OrderContext context) {
    }
}

确认收货

package com.lxl.www.designPatterns.statePattern.order2;
public class Confirm implements IOrderStatus{
    public Confirm() {
        System.out.println("当前状态 :: 确认收货");
    }
    @Override
    public void pending(OrderContext context) {
    }
    @Override
    public void cancelPay(OrderContext context) {
    }
    @Override
    public void waitOut(OrderContext context) {
    }
    @Override
    public void refunds(OrderContext context) {
        System.out.println("申请退款");
        context.setOrderStatus(new Refunds());
    }
    @Override
    public void waitReceive(OrderContext context) {
    }
    @Override
    public void confirmReceived(OrderContext context) {
        System.out.println("确认收货了");
        context.setOrderStatus(new OrderEvaluation());
    }
    @Override
    public void orderEvaluation(OrderContext context) {
    }
    @Override
    public void finish(OrderContext context) {
    }
}

订单评价

package com.lxl.www.designPatterns.statePattern.order2;
import com.sun.tools.corba.se.idl.constExpr.Or;
/**
 * 订单评价
 */
public class OrderEvaluation implements IOrderStatus {
    public OrderEvaluation() {
        System.out.println("当前状态 :: 订单待评价");
    }
    @Override
    public void pending(OrderContext context) {
    }
    @Override
    public void cancelPay(OrderContext context) {
    }
    @Override
    public void waitOut(OrderContext context) {
    }
    @Override
    public void refunds(OrderContext context) {
    }
    @Override
    public void waitReceive(OrderContext context) {
    }
    @Override
    public void confirmReceived(OrderContext context) {
    }
    @Override
    public void orderEvaluation(OrderContext context) {
        System.out.println("订单评价完了");
        context.setOrderStatus(new Finish());
    }
    @Override
    public void finish(OrderContext context) {
    }
}

订单完成

package com.lxl.www.designPatterns.statePattern.order2;
/**
 * 订单完成
 */
public class Finish implements IOrderStatus {
    @Override
    public void pending(OrderContext context) {
    }
    @Override
    public void cancelPay(OrderContext context) {
    }
    @Override
    public void waitOut(OrderContext context) {
    }
    /*
     * 退货退款
     */
    public void refunds(OrderContext context) {
    }
    @Override
    public void waitReceive(OrderContext context) {
    }
    @Override
    public void confirmReceived(OrderContext context) {
    }
    @Override
    public void orderEvaluation(OrderContext context) {
    }
    @Override
    public void finish(OrderContext context) {
        System.out.println("订单完成");
    }
}

取消付款

package com.lxl.www.designPatterns.statePattern.order2;
/**
 * 取消付款
 */
public class CancelPay implements IOrderStatus {
    @Override
    public void pending(OrderContext context) {
    }
    /*
     * 取消付款
     */
    public void cancelPay(OrderContext context) {
    }
    @Override
    public void waitOut(OrderContext context) {
    }
    /*
     * 退货退款
     */
    public void refunds(OrderContext context) {
    }
    @Override
    public void waitReceive(OrderContext context) {
    }
    @Override
    public void confirmReceived(OrderContext context) {
    }
    @Override
    public void orderEvaluation(OrderContext context) {
    }
    @Override
    public void finish(OrderContext context) {
    }
}

退货退款

package com.lxl.www.designPatterns.statePattern.order2;
public class Refunds implements IOrderStatus{
    public Refunds() {
        System.out.println("当前状态 :: 退货退款");
    }
    @Override
    public void pending(OrderContext context) {
    }
    @Override
    public void cancelPay(OrderContext context) {
    }
    @Override
    public void waitOut(OrderContext context) {
    }
    @Override
    public void refunds(OrderContext context) {
        System.out.println("退款完成");
        context.setOrderStatus(new Finish());
    }
    @Override
    public void waitReceive(OrderContext context) {
    }
    @Override
    public void confirmReceived(OrderContext context) {
    }
    @Override
    public void orderEvaluation(OrderContext context) {
    }
    @Override
    public void finish(OrderContext context) {
    }
}

我们看得出来, 这些状态子类,继承了父类所有的方法,但是却没有实现所有的方法。而是只实现了和自己有关系的一部分方法。这也是我们后面需要优化的地方

第四步: 客户端调用

package com.lxl.www.designPatterns.statePattern.order2;
public class OrderClient {
    public static void main(String[] args) {
        System.out.println("==========张三   开始下单==========");
        OrderContext o1 = new OrderContext();
        System.out.println("===========取消付款==============");
        o1.cancelPay();
        o1.finish();
        System.out.println();
        System.out.println();
        System.out.println("==========李四    开始下单==========");
        OrderContext o2 = new OrderContext();
        System.out.println("===========付款==============");
        o2.pending();
        System.out.println("===========退货退款==============");
        o2.refunds();
        o2.refunds();
        o2.finish();
        System.out.println();
        System.out.println();
        System.out.println("==========王五    开始下单==========");
        OrderContext o3 = new OrderContext();
        System.out.println("===========付款==============");
        o3.pending();
        System.out.println("===========出库==============");
        o3.waitOut();
        System.out.println("===========收货==============");
        o3.waitReceive();
        System.out.println("===========确认收货==============");
        o3.confirmReceived();
        System.out.println("===========订单评价==============");
        o3.orderEvaluation();
        System.out.println("===========订单完成==============");
        o3.finish();
    }
}

来看看运行效果:

张三 开始下单


开始购物


当前状态::待付款


=取消付款====


取消付款


订单完成

李四 开始下单


开始购物


当前状态::待付款


=付款

付款完成了, 待出库

当前状态::待出库

=退货退款


申请退货


当前状态 :: 退货退款


退款完成


订单完成

王五 开始下单


开始购物


当前状态::待付款


=付款

付款完成了, 待出库

当前状态::待出库

=出库


出库完成, 待收货


当前状态 :: 待收货


=收货

进行收货, 完成收货动作

当前状态 :: 确认收货

=确认收货


确认收货了


当前状态 :: 订单待评价


=订单评价

订单评价完了

=订单完成


订单完成

第三种:完善方案二


方案二违背了接口隔离原则。胖接口,导致很多类其实都不需要重写方法,但是不得不继承。实际工作中,我们可以将胖接口拆分,这样状态子类只需要实现自己需要的接口就可以了。


今天这里还有一种特别的解决方案,也可以很巧妙的解决这个问题。


第一步: 定义环境上下文类


观察一下,这次的环境上下文类和方案二的有什么区别?


对每一个状态进行的强转。这样做的优点后面就可以看出来了


package com.lxl.www.designPatterns.statePattern.order3;
/**
 * 订单上下文
 */
public class OrderContext {
    /**在上下文类中记录订单状态*/
    private IOrderStatus orderStatus;
    public OrderContext() {
        System.out.println("开始购物");
        // 最开始是待付款状态
        this.orderStatus = new Pending();
    }
    public void setOrderStatus(IOrderStatus orderStatus) {
        this.orderStatus = orderStatus;
    }
    /**
     * 去付款
     */
    public void toPay() {
        ((Pending)this.orderStatus).toPay(this);
    }
    /**
     * 取消付款
     */
    public void toCancelPay() {
        ((Pending)this.orderStatus).toCancelPay(this);
    }
    /**
     * 取消付款
     */
    public void cancelPay() {
        ((CancelPay)this.orderStatus).cancelPay(this);
    }
    /**
     * 去发货
     */
    public void toSendProduct() {
        ((WaitOut)this.orderStatus).toSendProduct(this);
    }
    /**
     * 申请退款
     */
    public void toRefunds() {
        ((Confirm)this.orderStatus).toRefunds(this);
    }
    /**
     * 已退款
     */
    public void refunded() {
        ((Refunds)this.orderStatus).refunded(this);
    }
    public void toReceiveProduct() {
        ((WaitReceive)this.orderStatus).toReceiveProduct(this);
    }
    /**
     * 点击确认收货按钮
     */
    public void toConfirmReceived() {
        ((Confirm)this.orderStatus).toConfirmReceived(this);
    }
    /**
     * 去评价订单
     */
    public void toOrderEvaluation() {
        ((OrderEvaluation)this.orderStatus).toOrderEvaluation(this);
    }
    /**
     * 已完成
     */
    public void finish() {
        ((Finish)this.orderStatus).finish(this);
    }
}

第二步: 定义抽象状态类


package com.lxl.www.designPatterns.statePattern.order3;
/**
 * 订单状态
 */
public interface IOrderStatus {
}

抽象状态类里面并没有方法


第三步: 定义具体状态实现


待付款

package com.lxl.www.designPatterns.statePattern.order3;
/**
 * 待付款
 */
public class Pending implements IOrderStatus {
    public Pending() {
        System.out.println("当前状态::待付款");
    }
    public void toPay(OrderContext context) {
        System.out.println("付款完成了, 待出库");
        context.setOrderStatus(new WaitOut());
    }
    /*
     * 取消付款
     */
    public void toCancelPay(OrderContext context) {
        System.out.println("不想要了, 要取消付款");
        context.setOrderStatus(new CancelPay());
    }
}

待出库

package com.lxl.www.designPatterns.statePattern.order3;
/**
 * 待出库
 */
public class WaitOut implements IOrderStatus {
    public WaitOut() {
        System.out.println("当前状态::待出库");
    }
    /*
     * 退货退款
     */
    public void toRefunds(OrderContext context) {
        System.out.println("不想要了, 申请退货退款");
        context.setOrderStatus(new Refunds());
    }
    /**
     * 去发货
     * @param context
     */
    public void toSendProduct(OrderContext context) {
        System.out.println("出库完成, 待收货");
        context.setOrderStatus(new WaitReceive());
    }
}

待收货

package com.lxl.www.designPatterns.statePattern.order3;
/**
 * 待收货
 */
public class WaitReceive implements IOrderStatus {
    public WaitReceive() {
        System.out.println("当前状态 :: 待收货");
    }
    /*
     * 退货退款
     */
    public void refunds(OrderContext context) {
        System.out.println("申请退货");
        context.setOrderStatus(new Refunds());
    }
    /**
     * 去收获
     * @param context
     */
    public void toReceiveProduct(OrderContext context) {
        System.out.println("执行收货逻辑, 完成收货操作");
        context.setOrderStatus(new Confirm());
    }
}

确认收货

package com.lxl.www.designPatterns.statePattern.order3;
public class Confirm implements IOrderStatus {
    public Confirm() {
        System.out.println("当前状态 :: 确认收货");
    }
    public void toRefunds(OrderContext context) {
        System.out.println("不想要了, 想退款");
        context.setOrderStatus(new Refunds());
    }
    public void toConfirmReceived(OrderContext context) {
        System.out.println("执行确认收货逻辑");
        context.setOrderStatus(new OrderEvaluation());
    }
}

订单评价

package com.lxl.www.designPatterns.statePattern.order3;
/**
 * 订单评价
 */
public class OrderEvaluation implements IOrderStatus {
    public OrderEvaluation() {
        System.out.println("当前状态 :: 订单待评价");
    }
    public void toOrderEvaluation(OrderContext context) {
        System.out.println("订单评价完了");
        context.setOrderStatus(new Finish());
    }
}

订单完成

package com.lxl.www.designPatterns.statePattern.order3;
/**
 * 订单完成
 */
public class Finish implements IOrderStatus {
    public void finish(OrderContext context) {
        System.out.println("订单完成");
    }
}

取消付款

package com.lxl.www.designPatterns.statePattern.order3;
/**
 * 取消付款
 */
public class CancelPay implements IOrderStatus {
    /*
     * 取消付款
     */
    public void cancelPay(OrderContext context) {
        System.out.println("执行取消付款逻辑");
        context.setOrderStatus(new Finish());
    }
}

退货退款

package com.lxl.www.designPatterns.statePattern.order3;
public class Refunds implements IOrderStatus {
    public Refunds() {
        System.out.println("当前状态 :: 退货退款");
    }
    public void refunded(OrderContext context) {
        System.out.println("完成退款");
        context.setOrderStatus(new Finish());
    }
}

第四步:客户端调用


package com.lxl.www.designPatterns.statePattern.order3;
public class OrderClient {
    public static void main(String[] args) {
        System.out.println("==========张三   开始下单==========");
        OrderContext o1 = new OrderContext();
        System.out.println("===========取消付款==============");
        o1.toCancelPay();
        o1.cancelPay();
        System.out.println("");
        System.out.println("");
        System.out.println("==========李四    开始下单  收货后退款==========");
        OrderContext o2 = new OrderContext();
        System.out.println("===========付款==============");
        o2.toPay();
        System.out.println("===========发货==============");
        o2.toSendProduct();
        System.out.println("===========收获==============");
        o2.toReceiveProduct();
        System.out.println("===========退货==============");
        o2.toRefunds();
        o2.refunded();
        System.out.println("===========完成==============");
        o2.finish();
        System.out.println();
        System.out.println();
        System.out.println("==========王五    开始下单走完全流程==========");
        OrderContext o3 = new OrderContext();
        System.out.println("===========付款==============");
        o3.toPay();
        System.out.println("===========出库==============");
        o3.toSendProduct();
        System.out.println("===========收货==============");
        o3.toReceiveProduct();
        System.out.println("===========确认收货==============");
        o3.toConfirmReceived();
        System.out.println("===========订单评价==============");
        o3.toOrderEvaluation();
        System.out.println("===========订单完成==============");
        o3.finish();
    }
}

运行结果:

张三 开始下单


开始购物


当前状态::待付款


=取消付款====


不想要了, 要取消付款


执行取消付款逻辑

李四 开始下单 收货后退款


开始购物


当前状态::待付款


=付款

付款完成了, 待出库

当前状态::待出库

=发货


出库完成, 待收货


当前状态 :: 待收货


=收获

执行收货逻辑, 完成收货操作

当前状态 :: 确认收货

=退货


不想要了, 想退款


当前状态 :: 退货退款


完成退款


=完成====


订单完成

王五 开始下单走完全流程


开始购物


当前状态::待付款


=付款

付款完成了, 待出库

当前状态::待出库

=出库


出库完成, 待收货


当前状态 :: 待收货


=收货

执行收货逻辑, 完成收货操作

当前状态 :: 确认收货

=确认收货


执行确认收货逻辑


当前状态 :: 订单待评价


=订单评价

订单评价完了

=订单完成


订单完成

运行结果和方案二是一样的


四、状态设计模式的优缺点



优点:


  • 结构清晰,避免了过多的switch…case或if…else语句的使用
  • 代码有很强的可读性。状态模式将每个状态的行为封装到对应的一个类中
  • 状态类职责明确,有利于程序的扩展。通过定义新的子类很容易地增加新的状态和转换。
  • 封装性非常好,状态变化放置到了类的内部来实现,外部调用不需要知道类内部如何实现状态和行为的变换


缺点:


  • 会产生很多类。每个状态都要一个对应的类,当状态过多时会产生很多类,加大维
    护难度
  • 违背开闭原则:增加一个状态,除了要增加状态子类,还需要修改原来的环境类。


五、应用场景



当一个事件或者对象有很多种状态,状态之间会相互转换,对不同的状态要求有不同的行为的时候,可以考虑使用状态模式

  • 电梯,有运行状态、开门状态、闭门状态、停止状态等
  • 一日从早到晚自身的状态,比如工作状态、学习状态、睡觉状态等等
  • 运动员可以有正常状态、非正常状态和超长状态


六、注意事项


  • 在行为受状态约束的情况下可以使用状态模式,使用时对象的状态最好不要超过5个。因为状态越多,逻辑越负责,后期维护成本越高。


七、状态模式对六大原则的使用分析


  • 单一职责原则: 符合单一职责原则,一个状态类只做一件事
  • 里式替换原则:父类出现的地方都可以使用子类替换。--- 状态模式父类是抽象类或者接口。方案一重写了父类的构造方法
  • 依赖倒置原则:依赖于抽象,而不是依赖于具体。---符合
  • 接口隔离原则:依赖于最小接口---方案二不符合
  • 迪米特法则:最小知识原则-之和朋友交流,减少和朋友的沟通 --- 符合
  • 开闭原则:对扩展开放,对修改关闭----增加状态需要修改原来的环境类---不符合


相关文章
|
并行计算 Java 数据处理
SpringBoot高级并发实践:自定义线程池与@Async异步调用深度解析
SpringBoot高级并发实践:自定义线程池与@Async异步调用深度解析
803 0
|
存储 缓存 安全
【服务器开发系列】订单号生成策略
订单是整个电子商务的核心,整个电子商务的流程也是围绕订单展开的;本文与大家分享一下各大电子商务网站订单号的生成方式。
1174 0
|
Java Linux iOS开发
Typora最新版破解, 2022年11.7破解成功
Typora最新版破解, 2022年11.7破解成功, 支持Linux, Windows, Mac三端破解, 你值得拥有哦
|
8月前
|
JSON API 数据格式
微店商品列表接口(微店 API 系列)
微店商品列表接口是微店API系列的一部分,帮助开发者获取店铺中的商品信息。首先需注册微店开发者账号并完成实名认证,选择合适的开发工具如PyCharm或VS Code,并确保熟悉HTTP协议和JSON格式。该接口支持GET/POST请求,主要参数包括店铺ID、页码、每页数量和商品状态等。响应数据为JSON格式,包含商品详细信息及状态码。Python示例代码展示了如何调用此接口。应用场景包括商品管理系统集成、数据分析、多平台数据同步及商品展示推广。
|
6月前
|
人工智能 供应链 机器人
AI浪潮下,大中型企业如何打造智能型的CRM系统
本文分析了纷享销客CRM作为大中型企业智能化转型伙伴的核心优势。其“连接型CRM”理念结合PaaS平台灵活性,实现企业内外部深度协同;AI能力场景化赋能销售与服务,提升效率与体验;功能全面且集成性强,支持复杂业务需求。尽管初始投入较高,但其市场验证的增长表现和战略价值,使其成为大中型企业构建长期竞争优势的优选方案。
|
12月前
|
机器学习/深度学习 算法 搜索推荐
深度学习之差分隐私
基于深度学习的差分隐私是一种在保护用户隐私的同时使用数据进行模型训练的技术。它的核心理念是通过加入随机噪声来隐藏个体数据的影响,防止在分析或模型训练过程中泄露个人信息。
1138 1
|
12月前
|
Docker 容器
docker:记录如何在x86架构上构造和使用arm架构的镜像
为了实现国产化适配,需将原x86平台上的Docker镜像转换为适用于ARM平台的镜像。本文介绍了如何配置Docker buildx环境,包括检查Docker版本、安装buildx插件、启用实验性功能及构建多平台镜像的具体步骤。通过这些操作,可以在x86平台上成功构建并运行ARM64镜像,实现跨平台的应用部署。
7801 2
|
Java Spring
Spring Boot使用策略模式指定Service实现类
Spring Boot使用策略模式指定Service实现类
294 0
|
Web App开发 前端开发 JavaScript
Spring Boot整合 mybatisplus(后端) Vue+echarts+Element UI+axios(前端)---前后端项目实例demo
Spring Boot整合 mybatisplus(后端) Vue+echarts+Element UI+axios(前端)---前后端项目实例demo
630 1
|
消息中间件 存储 RocketMQ
大白话-设计RocketMQ延迟消息
RocketMQ的延迟消息使用上非常便捷,但是不支持任意时间的延迟,这一点对于有强迫症的朋友来说就比较难受,但是搞明白为什么这么设计后,就自然释怀了。