Published on

有限状态机和状态模式

Authors

有限状态机(Finite-State Machine)是一种计算模型,状态模式是一种设计模式,两者不可同日而语。但是,有限状态机可以通过状态模式来实现。

所谓的有限,指的是状态个数是有限的,每个状态可以迁移到零个到多个状态,输入的时间决定了状态往哪个方向迁移。

有限状态机的特征是离散、有限。但是,世界上绝大多数事物,没有办法使用状态机来表示,这些事物的状态比较复杂,可能有无限多个。比如,经济增长的变化,温度的变化。

当前状态/条件状态A状态B
条件X......
条件Y状态B...

状态机可以归纳为:现态、事件、动作、次态。

  • 现态:指的是对象当前所处的状态
  • 事件:发生一个事件,可能执行状态迁移
  • 动作:发生一个事件后执行的操作。事件发生会触发相应的动作。此时可能发生状态的迁移,也可能不发生。
  • 次态:“次态”是相对于“现态”而言的,“次态”一旦被激活,就转变成新的“现态”了。

状态模式

状态模式,可以作为实现状态机的一种方式: 状态模式

在软件开发过程中,对象需要根据不同的情况做出不同的行为,影响对象行为的一个或者多个属性我们把它称为状态。当有外部事件影响对象的状态发生改变时,对象的行为也会发生改变。状态模式可以在一定程度上优化密集的 if-else或者switch-case代码,类似条件判断语句会过于臃肿,可读性差,且不具备扩展性,维护难度也大。

状态模式的核心要点是把复杂的逻辑判断提取出来,用不同的类来表示,系统处于哪种情况,就使用相应的状态类来进行处理,这样做就能简化逻辑的判断。

但是状态模式也有缺点,最大的缺点就是会增加系统中类的数量,以后新增状态也要新增类,也有一定的复杂度。

从上图可以看出,状态模式主要有:

  • Context 类:环境上下文,维护一个当前状态
  • State 类:抽象类,定义对象的状态和行为
  • ConcreteState 类:实现抽象对象所定义的行为

实现FSM

实现一个FSM包含了几个要素:状态的管理、状态的监控、状态的触发、状态触发后引发的动作。

状态模式实现
//抽象状态类
abstract class State {
    public abstract void Handle(Context context);
}
//具体状态A类
class ConcreteStateA extends State {
    public void Handle(Context context) {
        System.out.println("当前状态是 A.");
        context.setState(new ConcreteStateB());
    }
}
//具体状态B类
class ConcreteStateB extends State {
    public void Handle(Context context) {
        System.out.println("当前状态是 B.");
        context.setState(new ConcreteStateA());
    }
}

//环境类
class Context {
    private State state;
    //定义环境类的初始状态
    public Context() {
        this.state = new ConcreteStateA();
    }
    //设置新状态
    public void setState(State state) {
        this.state = state;
    }
    //读取状态
    public State getState() {
        return (state);
    }
    //对请求做处理
    public void Handle() {
        state.Handle(this);
    }
}
枚举实现
public interface IPositionFSM {

    default IPositionFSM processFoo() {
        return this;
    }

    default IPositionFSM processBar() {
        return this;
    }
}

public enum PositionFSM implements IPositionFSM {
    State1 {
        @Override
        public IPositionFSM processFoo() {
            return State2;
        }
    },
    State2 {
        @Override
        public IPositionFSM processBar() {
            return State1;
        }
    };
}

总结

状态模式实现FSM略显复杂,一般情况下推荐使用枚举的方式。


参考资料: