基本概念
- 有限狀態(tài)機(jī)FSM
- 描述事物的有限狀態(tài)機(jī)模型的元素由以下組成:
- 狀態(tài)(State):事物的狀態(tài)岛琼,包括初始狀態(tài)和所有事件觸發(fā)后的狀態(tài)
- 事件(Event):觸發(fā)狀態(tài)變化或者保持原狀態(tài)的事件
- 行為或轉(zhuǎn)換(Action/Transition):執(zhí)行狀態(tài)轉(zhuǎn)換的過(guò)程
- 檢測(cè)器(Guard):檢測(cè)某種狀態(tài)要轉(zhuǎn)換成另一種狀態(tài)的條件是否滿(mǎn)足
- http://www.reibang.com/p/37281543f506
- 深入淺出理解有限狀態(tài)機(jī)
- 狀態(tài)機(jī)的要素
- 狀態(tài)機(jī)可歸納為4個(gè)要素,即現(xiàn)態(tài)、條件奔缠、動(dòng)作蚕冬、次態(tài)浩考。“現(xiàn)態(tài)”和“條件”是因办陷,“動(dòng)作”和“次態(tài)”是果。詳解如下:
1. 現(xiàn)態(tài):是指當(dāng)前所處的狀態(tài)律歼。
2. 條件:又稱(chēng)為“事件”民镜。當(dāng)一個(gè)條件被滿(mǎn)足,將會(huì)觸發(fā)一個(gè)動(dòng)作苗膝,或者執(zhí)行一次狀態(tài)的遷移殃恒。
3. 動(dòng)作:條件滿(mǎn)足后執(zhí)行的動(dòng)作。動(dòng)作執(zhí)行完畢后辱揭,可以遷移到新的狀態(tài)离唐,也可以仍舊保持原狀態(tài)。動(dòng)作不是必需的问窃,當(dāng)條件滿(mǎn)足后亥鬓,也可以不執(zhí)行任何動(dòng)作,直接遷移到新?tīng)顟B(tài)域庇。
4. 次態(tài):條件滿(mǎn)足后要遷往的新?tīng)顟B(tài)嵌戈。“次態(tài)”是相對(duì)于“現(xiàn)態(tài)”而言的听皿,“次態(tài)”一旦被激活熟呛,就轉(zhuǎn)變成新的“現(xiàn)態(tài)”了。
代碼實(shí)現(xiàn)
- 定義狀態(tài)
public enum ProcessState {
INIT(0, "未開(kāi)始"),
READY_ONE_SIDE(1, "一方準(zhǔn)備完成"),
READY_ALL(2, "雙方準(zhǔn)備完成"),
CHAT(3, "發(fā)言完成"),
END(4, "結(jié)束"),
;
private int val;
private String desc;
ProcessState(int val, String desc) {
this.val = val;
this.desc = desc;
}
public int getVal() {
return val;
}
}
- 定義事件
public enum ProcessEvent {
READY_ONE_SIDE(1, "一方準(zhǔn)備"),
READY_ALL(2, "另一方準(zhǔn)備"),
CHAT(3, "發(fā)言"),
FORBID_ALL(4, "全員禁言"),
;
private Integer code;
private String desc;
ProcessEvent(Integer code, String desc) {
this.code = code;
this.desc = desc;
}
public Integer getCode() {
return code;
}
}
- 定義狀態(tài)機(jī)
public class ProcessEventConfig {
private ProcessEvent event;
private ProcessState fromState;
private ProcessState toState;
public String desc(){
return fromState.getDesc() + "_" + event.getDesc() + "_" + toState.getDesc();
}
}
List<ProcessEventConfig> configList = new ArrayList<>(16);
configList.add(new ProcessEventConfig(ProcessEvent.READY_ONE_SIDE, ProcessState.INIT, ProcessState.READY_ONE_SIDE));
configList.add(new ProcessEventConfig(ProcessEvent.READY_ALL, ProcessState.READY_ONE_SIDE, ProcessState.READY_ALL));
configList.add(new ProcessEventConfig(ProcessEvent.CHAT, ProcessState.READY_ALL, ProcessState.CHAT));
configList.add(new ProcessEventConfig(ProcessEvent.FORBID_ALL, ProcessState.CHAT, ProcessState.END));
Map<ProcessEvent, ProcessEventConfig> eventResultStateConfigMap = new EnumMap<>(ProcessEvent.class);
configList.forEach(eventConfig -> eventResultStateConfigMap.put(eventConfig.getEvent(), eventConfig));
- 觸發(fā)狀態(tài)變化
public boolean fire(ProcessEvent event, Process process) {
ProcessEventConfig config = Optional.ofNullable(eventResultStateConfigMap.get(event)).orElseThrow(() -> ExceptionCodeEnum.AGRS_INVALID.newException("不存在該事件"));
if (process.getStatus() != config.getFromState().getVal()) {
return false;
}
process.setRemark(config.desc());
process.setStatus(config.getToState().getVal());
//DB改變狀態(tài)
/*update table set status=${status} WHERE id={id} AND status=${beforeStatus}*/
boolean suc = processManager.updateStatus(process, config.getFromState().getVal());
if (suc) {
//變更成功尉姨,業(yè)務(wù)邏輯
}
return suc;
}