前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >透过源码学习设计模式5—状态模式和Spring状态机

透过源码学习设计模式5—状态模式和Spring状态机

作者头像
java达人
发布2019-08-15 17:27:56
5K0
发布2019-08-15 17:27:56
举报
文章被收录于专栏:java达人java达人
简介:

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

角色:

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

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

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

例子:

before :

代码语言:javascript
复制
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:

代码语言:javascript
复制
//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状态机来实现一个洗衣机的工作流程:

定义状态和事件枚举类:

代码语言:javascript
复制
public enum States { 

    RUNNING, HISTORY, END,

    WASHING, RINSING, DRYING,

    POWEROFF

}



public enum Events { 

    RINSE, DRY, STOP,

    RESTOREPOWER, CUTPOWER

}

状态机配置:状态

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

代码语言:javascript
复制
@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);

}

状态机配置:状态转化

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

代码语言:javascript
复制
@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、怎样做/什么&何时做:多种策略定义了做某事的多种方式。而多个状态定义要做什么,并基于状态之间的关系定义何时做。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-08-10,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 java达人 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 简介:
  • 角色:
  • 例子:
  • 一般使用场景:
  • 优缺点:
  • Spring State Machine示例:
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档