学习杂记---FSM(有限状态机)应用
FSM核心和作用
全称finite-state-machine,在有限个状态下,通过外部调用去发生状态的转移和其他动作的模型
分类
F(S) -> (A, S’) 型状态机:下一状态只由当前状态决定
F(S, E) -> (A, S’) 型状态机:下一状态不但与当前状态有关,还与当前输入值有关
下面是通过Java实现F(S, E) -> (A, S’) 型状态机的方式
Java实现
事件枚举
public enum EventEnum {
PASS
FAILED
MANUAL
}
Map的Key和Value维护
@AllArgsConstructor
@NoArgsConstructor
@Builder
@Data
public class FSMKey {
private boolean condition1;
private boolean condition2;
private StatusEnum sourceStatus;
private EventEnum event;
}
@AllArgsConstructor
@NoArgsConstructor
@Builder
@Data
public class FSMValue {
private StatusEnum targetStatus;
}
status_mapping
数据库数据仅供参考
condition1 | conditon2 | event |
---|---|---|
true | true | PASS |
true | false | PASS |
false | true | PASS |
false | false | PASS |
true | true | FAILED |
true | false | FAILED |
false | false | MANUAL |
public interface StatusService {
//sourceStatus表示当前状态,最后会把转移后的状态return;
//通过event和condition1,condition2去映射到要转移到状态
StatusEnum action(boolean condition1, boolean condition2,
StatusEnum sourceStatus, EventEnum event);
}
@Service
public class StatusServiceImpl implements StatusService {
/**
* 在第一次调用action的时候,构建一个fsmMap,去match要转移的状态
*/
private volatile Map<FSMKey, FSMValue> fsmMap;
/**
* 因为condition和event的组合情况较多,所以将映射关系存在数据库中的staus_mapping表
* PS:个人理解通过Apollo之类的配置中心也很好
*/
private void initFSMMapIfNeed() {
if (fsmMap == null) {
synchronized (this) {
if (fsmMap == null) {
fsmMap = new HashMap<>();
List<StatusMapping> mappingList = statusMappingService.list();
mappingList.forEach(mapping ->
fsmMap.put(
FSMKey.builder()
.condition1(mapping.getCondition1())
.condition2(mapping.getCondition2())
.sourceStatus(mapping.getSourceStatus())
.event(mapping.getEvent())
.build(),
new FSMValue(mapping.getTargetStatus())
)
);
}
}
}
}
public StatusEnum action(boolean condition1, boolean condition2,
StatusEnum sourceStatus, EventEnum event) {
initFSMMapIfNeed();
FSMKey key = FSMKey.builder()
.conditon1(conditon1)
.conditon2(conditon2)
.sourceStatus(sourceStatus)
.event(event)
.build();
FSMValue fsmValue = fsmMap.get(key);
if (fsmValue == null || fsmValue.getTargetStatus() == null) {
//throw exception;
}
return fsmValue.getTargetStatus();
}
}