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个。因为状态越多,逻辑越负责,后期维护成本越高。


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


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


相关文章
|
7月前
|
设计模式 存储
行为设计模式之状态模式
行为设计模式之状态模式
|
设计模式 前端开发 数据安全/隐私保护
前端实现设计模式之状态模式
状态模式是一种行为型设计模式,用于在对象内部状态发生变化时改变其行为。状态模式将对象的行为封装在不同的状态类中,使得对象在不同的状态下可以有不同的行为。在前端开发中,状态模式常用于管理组件的状态和行为,以实现复杂的交互逻辑。本文将介绍状态模式的概念和应用,并提供具体的代码示例和解读。
171 0
|
8月前
|
设计模式
【设计模式】状态模式
【设计模式】状态模式
|
8月前
|
设计模式 前端开发
【设计模式】之状态模式
状态模式是一种非常有用的设计模式,在前端开发中经常用于管理应用状态和处理复杂的流程。它通过将对象行为和属性与特定条件下的处理逻辑分离开来,提高了代码的可维护性和可扩展性。通过使用状态模式,我们可以优雅地管理应用状态,并根据不同的条件来改变对象行为。然而,在应用状态模式时需要权衡其带来的优缺点,并根据具体情况进行选择。
81 1
|
设计模式 C++ 开发者
设计模式之状态模式(C++)
设计模式之状态模式(C++)
|
设计模式 存储 算法
|
设计模式
设计模式之状态模式
设计模式之状态模式
68 0
|
设计模式
状态设计模式解读
状态设计模式解读
|
设计模式 消息中间件 Java
一起来学设计模式之状态模式
前言 目前正在出一个设计模式专题系列教程, 篇幅会较多, 喜欢的话,给个关注❤️ ~ 本节给大家讲一下设计模式中的状态模式,并结合实际业务场景给大家讲解如何使用~ 本专题的所有案例代码主要以Java语言为主, 好了, 废话不多说直接开整吧~ 状态模式 状态模式(State Pattern)是一种行为型设计模式,它允许一个对象在其内部状态改变时改变其行为。 在状态模式中,一个对象的状态被封装为一个对象,该状态对象则负责对象的行为变化。当对象的状态改变时,它会使用当前状态所对应的行为。
|
设计模式
23种设计模式——状态模式
状态模式是对有状态的对象,把复杂的“判断逻辑”提取到不同的状态对象中,允许状态对象在其内部状态发生改变时改变其行为。
174 0
23种设计模式——状态模式