状态模式

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


状态模式概念

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


状态模式的思想

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


案例(辅助理解)

情景说明

  简单的,在购买商品时,该商品会有对应的订单状态信息,如下图所示:
在这里插入图片描述

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

在这里插入图片描述

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

在这里插入图片描述

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

  • BillState:
    /**
     * 订单状态
     *
     * @author JustryDeng
     * @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 JustryDeng
     * @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 JustryDeng
     * @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 JustryDeng
     * @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 JustryDeng
     * @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方法,控制台输出:
在这里插入图片描述


状态模式学习完毕 !


^_^ 如有不当之处,欢迎指正

^_^ 参考资料
        《Head First 设计模式》
Eric Freeman & Elisabeth Freeman with Kathy Sierra & Bert Bates著,O’Reilly Taiwan公司译,UMLChina改编

^_^ 测试代码托管链接
         https://github.com/JustryDeng…DesignPattern

^_^ 本文已经被收录进《程序员成长笔记》 ,笔者JustryDeng

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值