6 Star 72 Fork 28

JustryDeng / notebook

Create your Gitee Account
Explore and code with more than 12 million developers,Free private repositories !:)
Sign up
Clone or Download
[02]状态模式.md 11.98 KB
Copy Edit Raw Blame History
邓沙利文 authored 2022-08-03 17:43 . 优化author

状态模式


声明 本文内容属于《Head First 设计模式》阅读笔记,文中涉及到的知识案例参考该书并发善编写。《Head First 设计模式》通过有趣的图表+文字的形式,让人自然学习设计模式,非常棒推荐阅读

状态模式概念

        允许对象在内部状态改变时改变它的行为,对象看起来就像修改了它的类。即:当一个对象的状态发生变化时,该对象所有与状态相关的方法的逻辑都会发生相应变化,(因为变化太大,所以)给人的感觉就像是换了一个对象(类实例)一样

状态模式的思想

  首先,将所有状态下的所有相关方法抽取到一个State总接口中,然后有多少个状态就创建多少个State实现,每个State实现需要根据自己的状态,对那些(该状态下支持的)方法进行业务逻辑编写,对(该状态下不支持的)方法进行不支持提示(或抛出异常)。   然后,当某个对象有状态的需求时。就可以使这个对象持有所有的State实现(即:持有所有可能的状态)。同时这个对象再设置一个currentState字段,用来指向当前所处的状态(即:指向当前对应的State实现)。当需要切换状态时,就改变currentState的指向。   最后,在这个对象需要调用到状态相关的方法时,直接使用currentState,而不直接使用对应的State实现。由于currentState是灵活指向不同的State实现的,所以当这个对象的状态发生变化时,currentState指向也会发生变化,那么即便调用的是同样的方法,也会走不同的逻辑(即:状态发生变化时,委派对象也发生了变化)。这样一来,对象在内部状态改变时就能改变它的行为,这个对象看起来就像修改了它的类一样,发生了翻天覆地的变化。

案例(辅助理解)

情景说明

简单的,在购买商品时,该商品会有对应的订单状态信息,如下图所示:

在这里插入图片描述

按照状态模式的思想,我们先抽取State接口并实现所有可能的状态

在这里插入图片描述

因为商品有状态需求,所以在商品中持有转态

在这里插入图片描述

上述状态模式示例中的几个核心类及代表类

  • BillState

     /**
      * 订单状态
      *
      * @author <font size = "20" color = "#3CAA3C"><a href="https://gitee.com/JustryDeng">JustryDeng</a></font> <img src="https://gitee.com/JustryDeng/shared-files/raw/master/JustryDeng/avatar.jpg" />
      * @date 2020/4/6 14:47:36
      */
     public interface BillState {
     
         /**
          * 状态名
          *
          * return 状态名
          */
         String name();
     
         /**
          * (买家)购物
          */
         default void shopping() {
             throw new UnsupportedOperationException("状态【" + this.getClass().getSimpleName() + "】下, 不支持sopping操作");
         }
     
         /**
          * (商家)发货
          */
         default void shipping() {
             throw new UnsupportedOperationException("状态【" + this.getClass().getSimpleName() + "】下, 不支持shipping操作");
         }
     
         /**
          * (收寄中心)揽件
          */
         default void packaging() {
             throw new UnsupportedOperationException("状态【" + this.getClass().getSimpleName() + "】下, 不支持packaging操作");
         }
     
         /**
          * (物流)开始运输
          */
         default void transport() {
             throw new UnsupportedOperationException("状态【" + this.getClass().getSimpleName() + "】下, 不支持transport操作");
         }
     
         /**
          * (快递小哥)派送
          */
         default void dispatch() {
             throw new UnsupportedOperationException("状态【" + this.getClass().getSimpleName() + "】下, 不支持dispatch操作");
         }
     
         /**
          * (买家)签收 or 拒签
          *
          * @param accept
          *            true - 买家签收;
          *            false - 买家拒签
          */
         default void signAccept(boolean accept) {
             throw new UnsupportedOperationException("状态【" + this.getClass().getSimpleName() + "】下, 不支持signAccept操作");
         }
     }
  • DispatchState

     import com.szlaozicl.designpattern.status.GoodsLogisticsInfo;
     import com.szlaozicl.designpattern.status.status.BillState;
     import lombok.RequiredArgsConstructor;
     
     /**
      * 派送状态
      * <p>
      * 注: 在派送状态下,唯一能做的就是 => 等待买家签收或拒签
      *
      * @author <font size = "20" color = "#3CAA3C"><a href="https://gitee.com/JustryDeng">JustryDeng</a></font> <img src="https://gitee.com/JustryDeng/shared-files/raw/master/JustryDeng/avatar.jpg" />
      * @date 2020/4/6 15:46:03
      */
     @RequiredArgsConstructor
     public class DispatchState implements BillState {
     
         private final GoodsLogisticsInfo goodsLogisticsInfo;
     
         @Override
         public String name() {
             return "派送状态";
         }
     
         @Override
         public void signAccept(boolean accept) {
             if (accept) {
                 System.out.println("(买家签收, 交易完成。进入)已收货状态");
                 // 将状态置为 已收货状态
                 goodsLogisticsInfo.setCurrentBillState(goodsLogisticsInfo.getHasReceiptedState());
             } else {
                 System.out.println("(买家拒签, 交易完成。进入)已退货状态");
                 // 将状态置为 已退货状态
                 goodsLogisticsInfo.setCurrentBillState(goodsLogisticsInfo.getHasReturnedState());
             }
         }
     
     }
  • StartingState

     import com.szlaozicl.designpattern.status.GoodsLogisticsInfo;
     import com.szlaozicl.designpattern.status.status.BillState;
     import lombok.RequiredArgsConstructor;
     
     /**
      * 起始状态
      *
      * 注: 在起始状态下,唯一能做的就是 => 买
      *
      * @author <font size = "20" color = "#3CAA3C"><a href="https://gitee.com/JustryDeng">JustryDeng</a></font> <img src="https://gitee.com/JustryDeng/shared-files/raw/master/JustryDeng/avatar.jpg" />
      * @date 2020/4/6 15:46:03
      */
     @RequiredArgsConstructor
     public class StartingState implements BillState {
     
         private final GoodsLogisticsInfo goodsLogisticsInfo;
     
         @Override
         public String name() {
             return "起始状态";
         }
     
         @Override
         public void shopping() {
             System.out.println("(买家)购物");
             // 将状态置为 已购物状态
             goodsLogisticsInfo.setCurrentBillState(goodsLogisticsInfo.getHasShoppedState());
         }
     
     }
  • GoodsLogisticsInfo

     import com.szlaozicl.designpattern.status.status.BillState;
     import com.szlaozicl.designpattern.status.status.impl.*;
     import lombok.Data;
     
     /**
      * 商品物流信息
      *
      * @author <font size = "20" color = "#3CAA3C"><a href="https://gitee.com/JustryDeng">JustryDeng</a></font> <img src="https://gitee.com/JustryDeng/shared-files/raw/master/JustryDeng/avatar.jpg" />
      * @date 2020/4/6 14:47:04
      */
     @Data
     public class GoodsLogisticsInfo {
     
         /** 所有可能的状态 */
         private BillState startingState;
         private BillState hasShoppedState;
         private BillState hasShippedState;
         private BillState hasPackagedState;
         private BillState transportState;
         private BillState dispatchState;
         private BillState hasReceiptedState;
         private BillState hasReturnedState;
     
         /** 当前状态 */
         private BillState currentBillState;
     
         public GoodsLogisticsInfo() {
             this.startingState = new StartingState(this);
             this.hasShoppedState = new HasShoppedState(this);
             this.hasShippedState = new HasShippedState(this);
             this.hasPackagedState = new HasPackagedState(this);
             this.transportState = new TransportState(this);
             this.dispatchState = new DispatchState(this);
             this.hasReceiptedState = new HasReceiptedState();
             this.hasReturnedState = new HasReturnedState();
             this.currentBillState = this.startingState;
         }
     
         public void currStateInfo() {
             System.err.println("订单当前处于【" + currentBillState.name() + "】");
         }
     
         public void shopping() {
             currentBillState.shopping();
         }
     
         public void shipping() {
             currentBillState.shipping();
         }
     
         public void packaging() {
             currentBillState.packaging();
         }
     
         public void transport() {
             currentBillState.transport();
         }
     
         public void dispatch() {
             currentBillState.dispatch();
         }
     
         public void signAccept(boolean accept) {
             currentBillState.signAccept(accept);
         }
     }

测试一下

  • 测试类:
     /**
      * 状态模式 --- 测试
      *
      * @author <font size = "20" color = "#3CAA3C"><a href="https://gitee.com/JustryDeng">JustryDeng</a></font> <img src="https://gitee.com/JustryDeng/shared-files/raw/master/JustryDeng/avatar.jpg" />
      * @date 2020/4/6 9:33:50
      */
     public class Test {
     
         public static void main(String[] args) {
             GoodsLogisticsInfo gli = new GoodsLogisticsInfo();
             // 测试 - 做当前状态下能做的事
             gli.currStateInfo();
             gli.shopping();
             gli.currStateInfo();
             gli.shipping();
             gli.currStateInfo();
             gli.packaging();
             gli.currStateInfo();
             gli.transport();
             gli.currStateInfo();
             gli.dispatch();
             gli.currStateInfo();
             gli.signAccept(true);
             gli.currStateInfo();
     
             // 测试 - 做当前状态下不能做的事
             gli.signAccept(false);
         }
     }

运行测试类main方法,控制台输出:

在这里插入图片描述


状态模式学习完毕 !

相关资料

  • demo代码下载
  • 《Head First 设计模式》 Eric Freeman & Elisabeth Freeman with Kathy Sierra & Bert Bates著,O'Reilly Taiwan公司译,UMLChina改编
1
https://gitee.com/JustryDeng/notebook.git
git@gitee.com:JustryDeng/notebook.git
JustryDeng
notebook
notebook
master

Search