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


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


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


相关文章
|
设计模式 程序员
设计模式 | 模版方法
设计模式 | 模版方法
91 0
|
8月前
|
设计模式 Java 测试技术
设计模式之-降龙十八掌
设计模式之-降龙十八掌
69 0
|
设计模式 安全 Java
设计模式之单列模式
设计模式之单列模式
74 0
|
设计模式 安全 Java
设计模式~单列模式-01
单列模式 1、饿汉式 2、懒汉式(lazy loading) 3、双重检测 4、静态内部类
48 0
|
设计模式 数据可视化 程序员
设计模式到底是什么
设计模式到底是什么
96 1
|
设计模式 存储 NoSQL
为什么我们需要设计模式?
设计模式解决什么问题设计模式一直被认为是一门难以学习的课程。究其原因是因为我们不清楚设计模式在解决哪些问题方面发挥作用。简言之,设计是为了实现特定的目标,基于不断更新的局部知识来获得解决方案的过程。我们通常熟悉的范式是在几乎掌握所有知识的情况下解决问题,例如解数学题、物理题等。然而,在软件编程过程中,我们掌握的知识往往不充分,而且会不断更新,因此需要我们关注有哪些知识,没有哪些知识,可以获取哪些知
9348 1
|
设计模式 程序员
设计模式(二)
设计模式
138 1
|
设计模式 Java
23种设计模式-总揽篇
23种设计模式-总揽篇
23种设计模式-总揽篇
|
设计模式 数据可视化 程序员
设计模式(一)
设计模式
129 0
|
设计模式 存储 安全
设计模式(三)
设计模式
140 0

热门文章

最新文章