九折技术 九折技术
首页
  • Go
  • MIT-6824
  • 算法与数据结构
  • 面向对象
  • 代码整洁
  • 重构
  • 设计模式
  • 学习
  • 技术
  • 人文
关于
  • 网站
  • 资源
  • 分类
  • 标签
  • 归档
GitHub

HoldDie

长期有耐心,一切才刚刚开始!
首页
  • Go
  • MIT-6824
  • 算法与数据结构
  • 面向对象
  • 代码整洁
  • 重构
  • 设计模式
  • 学习
  • 技术
  • 人文
关于
  • 网站
  • 资源
  • 分类
  • 标签
  • 归档
GitHub
  • 代码整洁

  • 重构

  • 设计模式

    • 创建型-单例模式
    • 创建型-工厂模式
    • 创建型-建造者模式
    • 创建型-原型模式
    • 结构型-代理模式
    • 结构型-桥接模式
    • 结构型-装饰器模式
    • 结构型-适配器模式
    • 结构型-门面模式
    • 结构型-组合模式
    • 结构型-享元模式
    • 行为型-观察者模式
    • 行为型-模板模式
    • 行为型-策略模式
    • 行为型-责任链模式
    • 行为型-状态模式
      • 行为型-迭代器模式
      • 行为型-访问者模式
      • 行为型-备忘录模式
      • 行为型-命令模式
      • 行为型-解释器模式
      • 行为型-中介模式
    • 架构
    • 设计模式
    holddie
    2020-10-14

    行为型-状态模式

    # 有限状态机

    • Finite State Machine(FSM)
    • 状态机由三部分组成:状态(State)、事件(Event)、动作(Action)。
    • 事件也称为转移条件(Transition Condition),事件触发状态的转移及动作的执行,不过动作不是必须的,也可能只转移状态,不执行任何动作。
    • 三种实现方式:状态模式、分支逻辑法和查表法。

    # 状态机实现方法

    # 分支逻辑法

    • 利用 if-else 或者 switch-case 分支逻辑,参照状态转移图,将每一个状态转移原模原样地直译成代码。
    • 对于简单的状态机来说,这种实现方式最简单、最直接,是首选。
    
    public class MarioStateMachine {
      private int score;
      private State currentState;
    
      public MarioStateMachine() {
        this.score = 0;
        this.currentState = State.SMALL;
      }
    
      public void obtainMushRoom() {
        if (currentState.equals(State.SMALL)) {
          this.currentState = State.SUPER;
          this.score += 100;
        }
      }
    
      public void obtainCape() {
        if (currentState.equals(State.SMALL) || currentState.equals(State.SUPER) ) {
          this.currentState = State.CAPE;
          this.score += 200;
        }
      }
    
      public void obtainFireFlower() {
        if (currentState.equals(State.SMALL) || currentState.equals(State.SUPER) ) {
          this.currentState = State.FIRE;
          this.score += 300;
        }
      }
    
      public void meetMonster() {
        if (currentState.equals(State.SUPER)) {
          this.currentState = State.SMALL;
          this.score -= 100;
          return;
        }
    
        if (currentState.equals(State.CAPE)) {
          this.currentState = State.SMALL;
          this.score -= 200;
          return;
        }
    
        if (currentState.equals(State.FIRE)) {
          this.currentState = State.SMALL;
          this.score -= 300;
          return;
        }
      }
    
      public int getScore() {
        return this.score;
      }
    
      public State getCurrentState() {
        return this.currentState;
      }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59

    # 查表法

    • 对于状态很多、状态转移比较复杂的状态机来说,查表法比较合适。
    • 通过二维数组来表示状态转移图,能极大地提高代码的可读性和可维护性。
    image-20201014183657222
    
    public enum Event {
      GOT_MUSHROOM(0),
      GOT_CAPE(1),
      GOT_FIRE(2),
      MET_MONSTER(3);
    
      private int value;
    
      private Event(int value) {
        this.value = value;
      }
    
      public int getValue() {
        return this.value;
      }
    }
    
    public class MarioStateMachine {
      private int score;
      private State currentState;
    
      private static final State[][] transitionTable = {
              {SUPER, CAPE, FIRE, SMALL},
              {SUPER, CAPE, FIRE, SMALL},
              {CAPE, CAPE, CAPE, SMALL},
              {FIRE, FIRE, FIRE, SMALL}
      };
    
      private static final int[][] actionTable = {
              {+100, +200, +300, +0},
              {+0, +200, +300, -100},
              {+0, +0, +0, -200},
              {+0, +0, +0, -300}
      };
    
      public MarioStateMachine() {
        this.score = 0;
        this.currentState = State.SMALL;
      }
    
      public void obtainMushRoom() {
        executeEvent(Event.GOT_MUSHROOM);
      }
    
      public void obtainCape() {
        executeEvent(Event.GOT_CAPE);
      }
    
      public void obtainFireFlower() {
        executeEvent(Event.GOT_FIRE);
      }
    
      public void meetMonster() {
        executeEvent(Event.MET_MONSTER);
      }
    
      private void executeEvent(Event event) {
        int stateValue = currentState.getValue();
        int eventValue = event.getValue();
        this.currentState = transitionTable[stateValue][eventValue];
        this.score += actionTable[stateValue][eventValue];
      }
    
      public int getScore() {
        return this.score;
      }
    
      public State getCurrentState() {
        return this.currentState;
      }
    
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73

    # 状态模式

    • 对于状态并不多、状态转移也比较简单,但事件触发执行的动作包含的业务逻辑可能比较复杂的状态机来说,我们首选这种实现方式。
    
    public interface IMario {
      State getName();
      void obtainMushRoom(MarioStateMachine stateMachine);
      void obtainCape(MarioStateMachine stateMachine);
      void obtainFireFlower(MarioStateMachine stateMachine);
      void meetMonster(MarioStateMachine stateMachine);
    }
    
    public class SmallMario implements IMario {
      private static final SmallMario instance = new SmallMario();
      private SmallMario() {}
      public static SmallMario getInstance() {
        return instance;
      }
    
      @Override
      public State getName() {
        return State.SMALL;
      }
    
      @Override
      public void obtainMushRoom(MarioStateMachine stateMachine) {
        stateMachine.setCurrentState(SuperMario.getInstance());
        stateMachine.setScore(stateMachine.getScore() + 100);
      }
    
      @Override
      public void obtainCape(MarioStateMachine stateMachine) {
        stateMachine.setCurrentState(CapeMario.getInstance());
        stateMachine.setScore(stateMachine.getScore() + 200);
      }
    
      @Override
      public void obtainFireFlower(MarioStateMachine stateMachine) {
        stateMachine.setCurrentState(FireMario.getInstance());
        stateMachine.setScore(stateMachine.getScore() + 300);
      }
    
      @Override
      public void meetMonster(MarioStateMachine stateMachine) {
        // do nothing...
      }
    }
    
    // 省略SuperMario、CapeMario、FireMario类...
    
    public class MarioStateMachine {
      private int score;
      private IMario currentState;
    
      public MarioStateMachine() {
        this.score = 0;
        this.currentState = SmallMario.getInstance();
      }
    
      public void obtainMushRoom() {
        this.currentState.obtainMushRoom(this);
      }
    
      public void obtainCape() {
        this.currentState.obtainCape(this);
      }
    
      public void obtainFireFlower() {
        this.currentState.obtainFireFlower(this);
      }
    
      public void meetMonster() {
        this.currentState.meetMonster(this);
      }
    
      public int getScore() {
        return this.score;
      }
    
      public State getCurrentState() {
        return this.currentState.getName();
      }
    
      public void setScore(int score) {
        this.score = score;
      }
    
      public void setCurrentState(IMario currentState) {
        this.currentState = currentState;
      }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88

    # 状态机应用场景

    • 游戏、工作流引擎系统开发中。

    # 思考题

    状态模式的代码实现还存在一些问题,比如,状态接口中定义了所有的事件函数,这就导致,即便某个状态类并不需要支持其中的某个或者某些事件,但也要实现所有的事件函数。不仅如此,添加一个事件到状态接口,所有的状态类都要做相应的修改。针对这些问题,你有什么解决方法吗?

    • 可以在接口和实现类中间加一层抽象类解决此问题,抽象类实现状态接口,状态类继承抽象类,只需要重写需要的方法即可。
    编辑
    #状态模式
    上次更新: 2020/10/18, 14:10:00
    行为型-责任链模式
    行为型-迭代器模式

    ← 行为型-责任链模式 行为型-迭代器模式→

    最近更新
    01
    行为型-访问者模式
    11-24
    02
    行为型-备忘录模式
    11-24
    03
    行为型-命令模式
    11-24
    更多文章>
    Theme by Vdoing | Copyright © 2019-2020 HoldDie | MIT License
    • 跟随系统
    • 浅色模式
    • 深色模式
    • 阅读模式