设计模式22-状态模式:对象行为随状态变化
状态模式让对象在不同状态下自动改变行为订单、流程、设备、连接都有状态。状态一多if-else 会迅速失控。状态模式把每个状态封装成对象让对象行为跟随状态自然切换。一、痛点状态判断散落每个方法订单有“待支付、已支付、已发货、已完成、已取消”五个状态。不同状态下“取消”“退款”“确认收货”行为不同。直接写publicvoidcancel(){if(UNPAID.equals(status)){// 直接取消}elseif(PAID.equals(status)){// 退款后取消}elseif(SHIPPED.equals(status)){// 拦截物流后取消}else{thrownewIllegalStateException();}}每个方法都要重复这一套状态判断。新增一个状态所有相关方法都要改。状态模式的回答把状态定义成独立类把随状态变化的行为放进状态类里。订单对象只持有当前状态并委托给它执行。二、实现状态接口 → 具体状态 → 上下文第一步定义订单状态接口publicinterfaceOrderState{voidpay(OrderContextorder);voidship(OrderContextorder);voidcomplete(OrderContextorder);}第二步实现具体状态publicclassUnpaidStateimplementsOrderState{Overridepublicvoidpay(OrderContextorder){System.out.println([未支付] 支付成功进入已支付状态);order.setState(newPaidState());}Overridepublicvoidship(OrderContextorder){thrownewIllegalStateException(未支付订单不能发货);}Overridepublicvoidcomplete(OrderContextorder){thrownewIllegalStateException(未支付订单不能完成);}}publicclassPaidStateimplementsOrderState{Overridepublicvoidpay(OrderContextorder){System.out.println([已支付] 已支付无需重复支付);}Overridepublicvoidship(OrderContextorder){System.out.println([已支付] 发货进入已发货状态);order.setState(newShippedState());}Overridepublicvoidcomplete(OrderContextorder){System.out.println([已支付] 虚拟商品可直接完成);order.setState(newCompletedState());}}publicclassShippedStateimplementsOrderState{Overridepublicvoidpay(OrderContextorder){System.out.println([已发货] 已支付无需重复支付);}Overridepublicvoidship(OrderContextorder){System.out.println([已发货] 已发货无需重复发货);}Overridepublicvoidcomplete(OrderContextorder){System.out.println([已发货] 确认收货进入已完成状态);order.setState(newCompletedState());}}publicclassCompletedStateimplementsOrderState{Overridepublicvoidpay(OrderContextorder){System.out.println([已完成] 订单已完成);}Overridepublicvoidship(OrderContextorder){System.out.println([已完成] 订单已完成);}Overridepublicvoidcomplete(OrderContextorder){System.out.println([已完成] 订单已完成);}}第三步上下文委托状态处理publicclassOrderContext{privateOrderStatestate;publicOrderContext(){this.statenewUnpaidState();}publicvoidsetState(OrderStatestate){this.statestate;}publicvoidpay(){state.pay(this);}publicvoidship(){state.ship(this);}publicvoidcomplete(){state.complete(this);}}第四步业务调用不再出现状态判断OrderContextordernewOrderContext();order.pay();order.ship();order.complete();输出[未支付] 支付成功进入已支付状态 [已支付] 发货进入已发货状态 [已发货] 确认收货进入已完成状态三、状态模式与策略模式的差异维度状态模式策略模式谁决定切换状态对象内部主动切换客户端或上下文外部选择策略关注点对象行为随内部状态变化同接口下算法替换对象关系上下文持有当前状态上下文持有当前策略状态是“内部状态驱动自己变化”策略是“外部选择不同算法”。两者结构相似但意图不同。四、工程化提醒状态类可能爆炸状态很多、行为很多时类数量会明显上升可用状态机框架如 Spring StateMachine收口状态迁移要集中管理状态对象之间互相 new时间久了迁移关系会散落需用状态表或文档明确不变行为可以留在上下文中只有随状态变化的方法才放进状态类避免无意义复制。小结状态模式一句话把“状态”和“行为”绑定成对象让对象自己决定下一步。它消灭了跨方法的重复状态判断也让新增状态变成新增一个类而不是改一堆 if-else。