spring状态机怎么获取当前的事件 spring状态机原理_spring状态机怎么获取当前的事件

简介:

状态模式即允许一个对象在其内部状态改变时改变它的行为。对象看起来似乎修改了它的类,换句话说状态模式把所研究的对象的行为包装在不同的状态对象里,每一个状态对象都属于一个抽象状态类的一个子类。

spring状态机怎么获取当前的事件 spring状态机原理_状态机_02

角色:

(1)、Context:上下文,定义客户端可能调用的接口,并且保留一个具体状态类的实例。这个具体状态类的实例给出此环境对象的现有状态。

(2)、State:定义一个接口,用以封装环境对象的一个特定的状态所对应的行为。

(3)、ConcreteState:每一个具体状态类都实现了环境(Context)的一个状态所对应的行为。

例子:

before :

class ElectricFanControl {
    private int currentState;
    public ElectricFanControl() {
        currentState = 0;
    }
    public void pull() {
        if (currentState == 0) {
            currentState = 1;
            System.out.println("low speed");
        } else if (currentState == 1) {
            currentState = 2;
            System.out.println("medium speed");
        } else if (currentState == 2) {
            currentState = 3;
            System.out.println("high speed");
        } else {
            currentState = 0;
            System.out.println("turning off");
        }
    }
}
public class StateDemo {
    public static void main(String[] args) {
        ElectricFanControl electricFanControl = new ElectricFanControl();
        while (true) {
            System.out.print("Press ENTER");
            getLine();
            electricFanControl.pull();
        }
    }
    static String getLine() {
        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
        String line = null;
        try {
            line = in.readLine();
        } catch (IOException ex) {
            ex.printStackTrace();
        }
        return line;
    }
}

after:

//State接口:
public interface State {
    public void start(Context context);
    public void close(Context context);
}
//StartState 类:
class StartState implements State {
  @Override
  public void start(Context context) {
    System.out.println("do noting");
  }
  @Override
  public void close(Context context) {
    System.out.println("close State");
    context.setState(new CloseState());
  }
}
class CloseState implements State {
   @Override
  public void start(Context context) {
    System.out.println("start State");
     context.setState(new StartState());
  }
   @Override
  public void close(Context context) {
     System.out.println("do noting");
  }
}
class Context {
  private State state;
  public void setState(State state) {
    this.state = state;
  }
  public State getState() {
    return state;
  }
  public void start() {
    getState().start(this);
  }
  public void close() {
    getState().close(this);
  }
}
public class StatePatternDemo {
  public static void main(String... args) {
    Context context = new Context();
    // 初始为开始状态
    context.setState(new StartState());
    // 切换为关闭状态
    context.close();
    // 切换为开始状态
    context.start();
  }
}
一般使用场景:

控制对象状态转换的条件逻辑过于复杂,用处理特殊状态和状态转换的state类替换条件语句

优缺点:

优点:

简化复杂的状态改变逻辑,有利于代码的阅读、维护和扩展。

缺点:

状态类增加,设计复杂度提高

Spring State Machine示例:

状态机(状态模式的一种应用)在工作流或游戏等各种系统中有大量使用,如各种工作流引擎,它几乎是状态机的子集和实现,封装状态的变化规则。Spring状态机帮助开发者简化状态机的开发过程,让状态机结构更加层次化。

如下代码显示如何用Spring状态机来实现一个洗衣机的工作流程:

定义状态和事件枚举类:

public enum States { 
    RUNNING, HISTORY, END,
    WASHING, RINSING, DRYING,
    POWEROFF
}
public enum Events { 
    RINSE, DRY, STOP,
    RESTOREPOWER, CUTPOWER
}

状态机配置:状态

通过多次调用withStates() 定义分层state, 你可以使用parent() 指定这些特定state是其他state的子state。

@Override
public void configure(StateMachineStateConfigurer<States, Events> states) 
        throws Exception { 
    states
        .withStates()
            .initial(States.RUNNING)
            .state(States.POWEROFF)
            .end(States.END)
            .and()
            .withStates()
                .parent(States.RUNNING)
                .initial(States.WASHING)
                .state(States.RINSING)
                .state(States.DRYING)
                .history(States.HISTORY, History.SHALLOW);
}

状态机配置:状态转化

三种不同类型的转换:外部转换、内部转换和本地转换。转换要么由信号(发送到状态机的事件)触发,要么由计时器触发

@Override
public void configure(StateMachineTransitionConfigurer<States, Events> transitions) 
        throws Exception { 
    transitions
        .withExternal()
            .source(States.WASHING).target(States.RINSING)
            .event(Events.RINSE)
            .and()
        .withExternal()
            .source(States.RINSING).target(States.DRYING)
            .event(Events.DRY)
            .and()
        .withExternal()
            .source(States.RUNNING).target(States.POWEROFF)
            .event(Events.CUTPOWER)
            .and()
        .withExternal()
            .source(States.POWEROFF).target(States.HISTORY)
            .event(Events.RESTOREPOWER)
            .and()
        .withExternal()
            .source(States.RUNNING).target(States.END)
            .event(Events.STOP);
}

后续:与策略模式的比较

同:

1、子类的使用:状态和策略模式都通过状态/策略的不同派生子类来更改具体实现。

2、模式类图:状态模式和策略模式之间最大的相似性之一是它们的类图,除了类名之外,它们看起来几乎相同。这两种模式都定义了状态/策略基类,子状态/子策略都继承基类。

3、两者都遵循开闭原则:状态模式的Context是对修改关闭的,即关于状态如何被访问和使用的逻辑是固定的。但是各个状态是开放的,也就是说,可以通过扩展可以添加更多的状态。类似地,策略模式的context是对修改关闭的,但是各个策略的子类是开放可扩展的。

异:

1、模式意图:策略模式的意图或目的是拥有一系列可互换的算法,这些算法可以根据context和/或客户需求进行选择。而状态模式的目的是管理对象的状态以及对象的行为,对象的行为会随着状态的变化而变化。

2、客户端对策略/状态的感知:在策略模式实现中,所选择的策略依赖于客户端,因此客户端知道使用的是哪种策略。而在状态模式实现中,客户端与context交互以对对象进行操作,但不决定选择哪种状态。对象本身似乎根据客户端通过context进行的交互来更改其状态类。

3、context的引用:状态模式中的每个状态都持有context的引用。但是,策略模式中每个策略并不持有context的引用。

4、状态/策略之间的关系:状态模式中的不同状态彼此相关,例如作为前一个或者后一个状态等。这是因为在状态之间像有限状态机有一个流动。然而,策略模式只是从多个可用策略中选择一个策略,策略之间没有后者/前者的关系。

5、怎样做/什么&何时做:多种策略定义了做某事的多种方式。而多个状态定义要做什么,并基于状态之间的关系定义何时做。