声明: 本文
内容属于《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