标签: 有限状态机,Akka fsm,squirrel-foundation,java状态模式、责任链模式
1. 有限状态机的概念
有限状态机(英语:finite-state machine,缩写:FSM)又称有限状态自动机,简称状态机,是表示有限个状态以及在这些状态之间的转移和动作等行为的数学模型。
通常FSM包含几个要素:状态的管理、状态的监控、状态的触发、状态触发后引发的动作。
这些关系的意思可以这样理解:
State(S) x Event(E) -> Actions (A), State(S’)
如果我们当前处于状态S,发生了E事件, 我们应执行操作A,然后将状态转换为S’
下面展示最常见的表示:当前状态(B)和条件(Y)的组合指示出下一个状态(C)。完整的动作信息可以只使用脚注来增加。包括完整动作信息的FSM定义可以使用状态表。
条件↓当前状态→
状态A
状态B
状态C
条件X
…
…
…
条件Y
…
状态C
…
条件Z
…
…
…
2. 使用状态机的应用背景
在广告投放项目中由于复杂的广告投放逻辑,存在着大量的if-else 判断类似的硬编码,希望能借助对fsm模型的调研,找出理想的实现方式。
3.有限状态机的几种实现
3.1枚举类实现java状态模式
首先在枚举类中 定义state 和定义的抽象方法。
public enum JavaPlatformState {
// 定义state
OPEN{
@Override void exit(JavaPlatformMachine pm){super.exit(pm);}
@Override void valid(JavaPlatformMachine pm){
this.exit(pm);
if(pm.data.getValid_()){
pm.state =STEP1;
}else{
NotFound();
pm.state =OFF;
}
pm.state.entry(pm);
}
@Override
void first(JavaPlatformMachine pm) {}
@Override
void businessLine(JavaPlatformMachine pm) {}
@Override
void district(JavaPlatformMachine pm) {}
},
STEP1{
@Override void exit(JavaPlatformMachine pm){super.exit(pm);}
@Override
void valid(JavaPlatformMachine pm) {}
@Override void first(JavaPlatformMachine pm){
this.exit(pm);
if(!pm.data.getFirst_()){
pm.state =STEP2;
}else{
ReturnDimension();
pm.state =OFF;
}
pm.state.entry(pm);
}
@Override
void businessLine(JavaPlatformMachine pm) {}
@Override
void district(JavaPlatformMachine pm) {}
},
...
//状态模式 提取的接口 在常量实体类中实现抽象方法
abstract void valid(JavaPlatformMachine pm);
abstract void first(JavaPlatformMachine pm);
abstract void businessLine(JavaPlatformMachine pm);
abstract void district(JavaPlatformMachine pm);
}
在enum JavaPlatformState 中,除了状态模式 提取的接口外,添加了状态机的各种动作action实现
//状态机的各种动作action methode
void entry(JavaPlatformMachine pm){System.out.println("→"+pm.state.name());}
void exit(JavaPlatformMachine pm){System.out.println(pm.state.name()+"→ ");}
void NotFound(){System.out.println("NotFound");}
void ReturnDimension(){System.out.println("ReturnDimension");}
void PreciseAdvertising(){System.out.println("PreciseAdvertising");}
void Top9(){System.out.println("Top9");}
建立状态机实体,ContextData是封装条件的bean类,初始化状态OPEN,在状态机里定义action,调用对应state的相应的方法。
public class ContextData {
private Boolean isValid_;//广告位是否有效
private Boolean isFirst_;//是否第一次请求
private Boolean isBusinessLine_;//是否属于业务线广告位
private Boolean district_;//是否有地域
...
}
public class JavaPlatformMachine {
ContextData data = new ContextData();
JavaPlatformState state = JavaPlatformState.OPEN;
//Action
public void valid(){state.valid(this);}
public void first(){state.first(this);}
public void businessLine(){state.businessLine(this);}
public void district(){state.district(this);}
}
测试方法,初始化状态机,设置参数,按次序调用对应的Action
JavaPlatformMachine pm = new JavaPlatformMachine();
pm.data.setValid_(true);// 广告位是否有效
pm.data.setFirst_(false);// 是否第一次请求
pm.data.setBusinessLine_(true);//是否属于业务线广告位
pm.data.setDistrict_(true);//是否有地域
pm.valid();
pm.first();
pm.businessLine();
pm.district();
输出结果
OPEN→
→STEP1
STEP1→
→STEP2
STEP2→
→STEP3
STEP3→
Top9
→OFF
在设置参数下,最后状态调用Top9。
不过这种方式在枚举类中实现抽象方法,每个state下都要覆写(Override)action的抽象方法,显然不利于拓展。
3.2抽象类实现java状态模式
当一个类的某个成员变量的值变化时,可能导致多个行为表现得不同。将该成员变量封装成类型的模式,即为状态模式(state pattern)。即用多态来重构分支结构。
首先抽象状态类,定义一个接口以封装与Context的一个特定状态相关的行为
public abstract class State {
public abstract void Handle(StateModeContext context );
public abstract boolean isFinalflag();
}
Context类,维护一个State子类的实例,这个实例定义当前的状态。
public class StateModeContext
{
private State state;
private ContextData data ;
public ContextData getData() {
return data;
}
public void setData(ContextData data) {
this.data = data;
}
public State getState() {
return state;
}
public void setState(State state) {
this.state = state;
}
/// 定义Context的初始状态
public StateModeContext(State state , ContextData data )
{
this.data = data;
this.state = state;
}
/// 对请求做处理,并设置下一个状态
boolean trueFlag = true;
public void Request()
{
//如果当前step 是最后一步 nextStep 不执行
if(state.isFinalflag()){
trueFlag = false;
}
state.Handle(this);
}
}
最后定义各个状态子类
public class State404 extends State {
@Override
public void Handle(StateModeContext context) {
System.out.println("当前状态是 404 do something");
}
@Override
public boolean isFinalflag() {
return true;
}
}
其中设置一个FinalFlag 标识 是否是最终状态。
在下面state的子类里面进行条件判断,并设置下一个状态,这一点有点类似责任链模式(在抽象类中定义一个实例成员变量 next handler 的引用)
public class StateStep1 extends State {
@Override
public void Handle(StateModeContext context) {
System.out.println("当前状态是 step1");
ContextData data = context.getData();
if(data.getFirst_()){
System.out.println("step1 -> dimension(返回尺寸)");
context.setState(new StateDimension());
}else{
System.out.println("step1 -> step2");
context.setState(new StateStep2());
}
}
@Override
public boolean isFinalflag() {
return false;
}
}
测试类:设置初始化数据和初始化状态stateOpen,根据状态树的深度确定循环迭代次数,进行迭代。
public class StateModeTest {
public static void main(String[] args) {
// 设置Context的初始状态为ConcreteStateA
ContextData data = new ContextData(true,false,true,true);
StateModeContext context = new StateModeContext(new StateOpen(),data);
// 不断地进行请求,同时更改状态
int size = 4;// 请求迭代数
f