设计模式-状态模式

状态模式

定义

状态机模式

对象在内部改变的时候,行为也改变,不同的状态对应不同的行为。

应用场景

  • 网关的订单状态变化

  • 电梯的状态变化

    • 超载了不能关门

    • 没有到达对应的楼层是不能开门的

每一个状态下的行为是不一样的

更加关心不同状态对应的行为

程序中对于某个操作,大多都是使用if else switch case 等,这种方式对于复杂状态的判断有弊端,臃肿,可读性查,不具备扩展性,维护难度大。

我们转化思路,可考虑不同状态独立起来用不同的类标识,系统处于什么状态,直接使用对应的状态类来表示。

适用场景

  • 行为随状态改变而改变

  • 一个操作含有庞大的多分支结构,这些分支取决于对象的状态。

通用代码和类图

状态抽象角色

定义状态下的行为,可以有一个或者多个行为

public abstract class State {
    protected Context context;

    public void setContext(Context context) {
        this.context = context;
    }

    public abstract void handle();
}

具体状态类

具体实现状态的对应行为,在需要的情况下进行状态切换

具体状态类A

public class ConcreteStateA extends State {
    @Override
    public void handle() {
        System.out.println("StateA do action");
        // A状态完成后自动切换到B状态
        this.context.setState(Context.STATE_B);
        this.context.getState().handle();
    }
}

具体状态类B

public class ConcreteStateB extends State {
    @Override
    public void handle() {
        System.out.println("StateB do action");
    }
}

环境类角色

​ 定义客户端需要的接口,内部维护一个当前状态实例,并负责具体状态的切换

public class Context {
  public static final State STATE_A = new ConcreteStateA();
  public static final State STATE_B = new ConcreteStateB();
  // 默认状态A
  private State currentState = STATE_A;
  {
    STATE_A.setContext(this);
    STATE_B.setContext(this);
  }

  public void setState(State state) {
    this.currentState = state;
    this.currentState.setContext(this);
  }

  public State getState() {
    return this.currentState;
  }

  public void handle() {
    this.currentState.handle();
  }
}

Context类似于桥接模式,完成了抽象和具象之间的联系

具体业务场景

​ 我们在社区阅读文章时,如果觉得文章写的很好,我们就会评论、收藏两连发。

  • 如果处于登录情况下,我们就可以直接做评论,收藏这些行为。

  • 否则,跳转到登录界面,登录后再继续执行先前的动作。

  • 涉及的状态

    • 登录与未登录,

  • 行为评论,收藏。

订单

状态机

<dependency>
  <groupId>org.springframework.statemachine</groupId>
  <artifactId>spring-statemachine-core</artifactId>
  <version>2.0.1.RELEASE</version>
</dependency>
public interface StateMachine<S, E> extends Region<S, E> {
    State<S, E> getInitialState();

    ExtendedState getExtendedState();

    StateMachineAccessor<S, E> getStateMachineAccessor();

    void setStateMachineError(Exception var1);

    boolean hasStateMachineError();
}

订单默认有几种状态

状态status 行为 event

状态模式相关的设计模式

状态模式与责任链模式

状态模式和责任链模式都能消除讦分支过多的问题。

但某些情况下,状态模式中的状态可以理解为责任,那么这种情况下,两种模式都可以使用。

  • 从定义来看,状态模式强调的是一个对象内在状态的改变,而责任链模式强调的是外部节点对象间的改变。

  • 从其代码实现上来看,他们间最大的区别就是

    • 状态模式各个状态对象知道自己下ー个要进入的状态对象;

    • 而责任链模式并不清楚其下ー个节点处理对象,因为链式组装由客户端负责。

状态模式与策略模式

状态模式与策略模式状态模式和策略槙式的UML类图架构几乎完全一样,但他们的应用场景是不一样的。

  • 策略模式多种算法行为择其一都能满足,彼此之间是独立的,用户可自行更换策略算法;

  • 而状态模式各个状态间是存在相互关系的

    • 彼此之间在一定条件下存在自动切换状态效果

    • 且用户无法指定状态,只能设置初始状态。

优点

  1. 结构清晰:将状态独立为类,消除了冗余的if.lse或 switch.case语句,使代码更加筒洁, 提高系统可维护性;

  2. 将状态转换显示化:通常的对象内部都是使用数值类型来定义状态,状态的切换是通过赋值进行表现,不够直观;而使用状态类,在切换状态时,是以不同的类进行表示,转换目的更加明确;

  3. 状态类职责明确且具备扩展性。

缺点

  1. 类膨胀:如果一个事物具备很多状态,则会造成状态类太多

  2. 状态模式的结构与实现都较为复杂,如果使用不当将导致程序结构和代码的混乱

  3. 状态模式对开闭原则的支持并不太好,对于可以切换状态的状态模式,

    1. 増加新的状态类需要修改那些负责状态转换的源代码,

    2. 否则无法切换到新増状态而且修改某个状态类的行为也需修改对应类的代码

Last updated