写点什么

StatePattern- 状态模式

作者:梁歪歪 ♚
  • 2022 年 6 月 05 日
  • 本文字数:3044 字

    阅读完需:约 10 分钟

StatePattern-状态模式

状态模式

状态模式(State Pattern):又称为状态机模式(State Machine Pattern),是允许对象在内部状态发生改变的同时改变对象的行为,使得看起来像是修改了类一样,其核心就是给每一种状态绑定一种行为。


状态模式中的类的行为是由状态决定的,不同的状态有不同的行为。状态模式的意图是让一个对象在其内部改变时行为也随之一起改变。


示例:我们通过订单状态(待支付,待收货,已收货)的流转来举例说明...


  • 抽象的订单状态类AbstractOrderState.java


package cn.liangyy.state;
/** * 抽象的订单状态类 */public abstract class AbstractOrderState { //订单上下文,用来负责状态切换 protected OrderContext orderContext;
public AbstractOrderState(OrderContext orderContext) { this.orderContext = orderContext; }
/** * 待支付状态订单对应行为:支付 */ public abstract void payOrder();
/** * 已支付状态订单对应行为:发货 */ public abstract void deliver();
/** * 已收货状态订单对应行为:收货 */ public abstract void receiveGoods();}
复制代码


  • 待支付状态类WaitPaidOrderState.java


package cn.liangyy.state;
/** * 待支付状态类 */public class WaitPaidOrderState extends AbstractOrderState { public WaitPaidOrderState(OrderContext orderContext) { super(orderContext); }
/** * 待支付状态绑定支付行为 */ @Override public void payOrder() { System.out.println("支付成功!"); //切换状态 this.orderContext.setState(this.orderContext.waitDeliver); }
/** * 不是待支付状态订单的行为 */ @Override public void deliver() { System.out.println("对不起,请先支付!"); }
/** * 不是待支付状态订单的行为 */ @Override public void receiveGoods() { System.out.println("对不起,请先支付!"); }}
复制代码


  • 待发货状态类WaitDeliverOrderState.java


package cn.liangyy.state;
/** * 代发货状态类 */public class WaitDeliverOrderState extends AbstractOrderState { public WaitDeliverOrderState(OrderContext orderContext) { super(orderContext); }
/** * 不是代发货状态订单的行为 */ @Override public void payOrder() { System.out.println("你已经支付过了!"); }
@Override public void deliver() { System.out.println("商品已发货并送达!"); //切换状态 this.orderContext.setState(this.orderContext.receiveGoods); }
/** * 不是代发货状态订单的行为 */ @Override public void receiveGoods() { System.out.println("请不要着急,商品即将发货!"); }}
复制代码


  • 待收货状态类ReceiveGoodsOrderState.java


package cn.liangyy.state;
/** * 待收货状态类 */public class ReceiveGoodsOrderState extends AbstractOrderState { public ReceiveGoodsOrderState(OrderContext orderContext) { super(orderContext); }
/** * 不是待收货状态订单的行为 */ @Override public void payOrder() { System.out.println("你已经支付过了,请不要重复支付!"); }
/** * 不是待收货状态订单的行为 */ @Override public void deliver() { System.out.println("商品已发货并送达,请不要重复发货!"); }
@Override public void receiveGoods() { System.out.println("用户已收到商品,此次交易结束!"); }}
复制代码


  • 订单上下文类OrderContext.java


package cn.liangyy.state;
/** * 订单上下文类 */public class OrderContext { //待支付状态 AbstractOrderState waitPaid; //代发货状态 AbstractOrderState waitDeliver; //待收货状态 AbstractOrderState receiveGoods;
//当前状态 AbstractOrderState currState;
public OrderContext() { //初始化 待支付 状态订单 this.waitPaid = new WaitPaidOrderState(this); //初始化 待发货 状态订单 this.waitDeliver = new WaitDeliverOrderState(this); //初始化 待收货 状态订单 this.receiveGoods = new ReceiveGoodsOrderState(this); //当前状态,默认待支付 currState = waitPaid; }
void setState(AbstractOrderState state){ this.currState = state; }
//支付 public void payOrder(){ currState.payOrder(); }
//发货 public void deliver(){ currState.deliver(); }
//收货 public void receiveGoods(){ currState.receiveGoods(); }}
复制代码


  • 测试TestState.java


package cn.liangyy.state;
/** * 状态模式-测试 */public class TestState { public static void main(String[] args) { //创建订单上下文,默认待支付状态 OrderContext orderContext = new OrderContext(); //支付,支付完成之后状态自动切换到待发货 orderContext.payOrder(); //发货,发货完成之后状态自动切换到待收货 orderContext.deliver(); //收货 orderContext.receiveGoods(); }}
复制代码


上述例子就是一个状态的全部流程,看起来是一个状态一个状态的往下执行,有点类似责任链模式,但是这两种模式肯定是不等价的。


状态模式和责任链模式状态模式、责任链模式都是一条链去处理,可以这么说在某种场景下这两种模式可以互相替换,但是这两种模式也是有本质区别的:


  • 状态模式的下一个节点是各个状态对象已经了解的,而且状态的流转就是由内部进行流转,客户端无法决定。

  • 责任链模式“链路”上的对象并不知道下一个节点处理人是谁,而是由客户端自行组装决定的。


状态模式和策略模式状态模式和策略模式都能用来消除大量的 if/else 场景,但是也有本质区别:


  • 策略模式中各个策略之间是独立的,相互可以替换,任意选择其中一个策略就能满足需求,而且是由客户端自己做出选择。

  • 而状态模式客户端只能选择初始节点,后续就会自动流转,各个状态是一个整体,不存在可以互相替换的状态。


状态模式适用场景当控制一个对象状态的条件表达式过于复杂的时候,就可以考虑使用状态模式,通过把状态的判断逻辑转移到表示不同状态的一系列类中,这样就可以把复杂的逻辑简单化,使得对象的行为依赖于它的状态,并且会随着状态的改变而同时改变行为。


状态模式优点


  • 通过将每个状态设置为独立的对象,消除了代码中存在的大量 if/else 等判断分支,使得代码更加简洁,更容易维护。

  • 将不同的状态通过不同的类来表示,使得状态切换时相比较于用数字或者字符串来表示时更加直观,转换目的也更加明确。

  • 每个状态类的职责单一明确,符合单一职责原则。


状态模式缺点


  • 状态过多会引起类膨胀。

  • 状态模式的结构与实现相对较为复杂,容易造成代码混乱。

  • 对于支持状态切换的状态类违反了开闭原则,因为一旦状态修改或者中间要新增状态,则需要修改对应的源代码,否则会出现状态切换错误。

发布于: 刚刚阅读数: 3
用户头像

梁歪歪 ♚

关注

时间带走了年少轻狂,无知沉淀了冷暖自知。 2021.07.22 加入

互联网行业摸爬滚打的Java后生一枚,希望在InfoQ能够充实自己的同时,结识更多大牛。

评论

发布
暂无评论
StatePattern-状态模式_设计模式_梁歪歪 ♚_InfoQ写作社区