狀態機的介紹與使用
狀(zhuang)態(tai)(tai)(tai)機(State Machine)是一種設計(ji)模式,用于描述對象在不(bu)同狀(zhuang)態(tai)(tai)(tai)之間的轉(zhuan)換和行(xing)為(wei)。狀(zhuang)態(tai)(tai)(tai)機可以幫助開(kai)發者管理復雜的狀(zhuang)態(tai)(tai)(tai)邏輯,使得(de)系統在不(bu)同狀(zhuang)態(tai)(tai)(tai)下(xia)的行(xing)為(wei)更易于理解和維護。以下(xia)是關于狀(zhuang)態(tai)(tai)(tai)機設計(ji)模式的詳細(xi)介紹(shao)。
1. 狀態機的基本概念
- 狀態:表示對象在某一時刻的情況或條件。例如,訂單的狀態可以是“新建”、“處理中”、“已完成”。
- 事件:導致狀態變化的觸發器,例如用戶操作、時間到達或其他外部輸入。
- 狀態轉移:從一個狀態到另一個狀態的過程,通常由事件驅動。
- 上下文:持有狀態機當前狀態及相關數據的對象。
2. 狀態機的組成部分
狀態機通常由以(yi)下幾個組(zu)成(cheng)(cheng)部分構成(cheng)(cheng):
- 狀態(States):定義了系統可能處于的所有狀態。
- 事件(Events):觸發狀態變遷的事件。
- 轉移(Transitions):描述狀態之間的轉換規則,通常與特定事件關聯。
- 行為(Actions):在狀態進入、退出或轉移時執行的操作。
3. 狀態機的類型
狀(zhuang)態機可以分(fen)為(wei)兩種主要(yao)類型:
- 有限狀態機(Finite State Machine, FSM):狀態數量有限,適用于大多數場景。
- 層次狀態機(Hierarchical State Machine):允許狀態嵌套,可以更好地組織復雜的狀態邏輯。
4. 狀態機的優點
- 清晰性:將狀態和行為明確分開,使代碼更加易讀和可維護。
- 靈活性:便于修改和擴展狀態邏輯,例如添加新的狀態或事件。
- 可測試性:每個狀態和轉移都可以獨立測試,提高了系統的可靠性。
5. 狀態機的實現
狀態機可以通過多種方式實現,常見的方法包括:
-
使用條件語句(if-else 或 switch-case):簡單的(de)狀態機可以(yi)用條件(jian)(jian)語句直接實現,但隨(sui)著(zhu)狀態和事(shi)件(jian)(jian)的(de)增加,代碼(ma)會變得復雜且難以(yi)維(wei)護。
-
狀態模式(State Pattern):一種面(mian)向對象(xiang)的(de)設(she)計模式,通過創(chuang)建狀(zhuang)(zhuang)態(tai)類來封裝(zhuang)狀(zhuang)(zhuang)態(tai)相關的(de)行為(wei),實現動態(tai)狀(zhuang)(zhuang)態(tai)切換。
-
狀態機框架:使用現有的狀態機庫或框架(如
Stateless4j、Spring State Machine等)來簡(jian)化(hua)狀態機(ji)的創建和(he)管理。
6. 狀態模式示例
下面是一個使(shi)用狀(zhuang)態(tai)模式實現簡單狀(zhuang)態(tai)機的示例,展(zhan)示如何管理訂單的狀(zhuang)態(tai)。
// 定義狀態接口
interface OrderState {
void handle(OrderContext context);
}
// 具體狀態實現
class NewOrderState implements OrderState {
public void handle(OrderContext context) {
System.out.println("Handling new order.");
context.setState(new ProcessingOrderState());
}
}
class ProcessingOrderState implements OrderState {
public void handle(OrderContext context) {
System.out.println("Processing order.");
context.setState(new CompletedOrderState());
}
}
class CompletedOrderState implements OrderState {
public void handle(OrderContext context) {
System.out.println("Order completed.");
}
}
// 上下文類
class OrderContext {
private OrderState state;
public OrderContext() {
this.state = new NewOrderState(); // 初始狀態
}
public void setState(OrderState state) {
this.state = state;
}
public void request() {
state.handle(this);
}
}
// 客戶端代碼
public class StatePatternDemo {
public static void main(String[] args) {
OrderContext order = new OrderContext();
order.request(); // 處理新訂單
order.request(); // 處理中的訂單
order.request(); // 訂單已完成
}
}
7. 總結
狀(zhuang)(zhuang)態(tai)機(ji)設(she)計模(mo)式是(shi)管理(li)復雜(za)狀(zhuang)(zhuang)態(tai)和(he)行為的(de)(de)一種有效方法。通過將狀(zhuang)(zhuang)態(tai)、事件和(he)轉(zhuan)移(yi)邏輯清晰地分開,狀(zhuang)(zhuang)態(tai)機(ji)使(shi)得(de)程序的(de)(de)結構更加清晰,易于理(li)解和(he)維護。無(wu)論是(shi)在游戲開發、工(gong)作(zuo)流(liu)管理(li)還是(shi)其他需要狀(zhuang)(zhuang)態(tai)管理(li)的(de)(de)應用中,狀(zhuang)(zhuang)態(tai)機(ji)都是(shi)一種非常有用的(de)(de)工(gong)具。使(shi)用現(xian)有的(de)(de)狀(zhuang)(zhuang)態(tai)機(ji)框架可以進一步簡化開發過程,提高效率。
輕量級狀態機stateless4j的使用
- 項目地址:
- 可以把當前狀態和狀態字段持久化的數據庫里,實例中存儲到文件里
resources/stateless.json
[
{
"state": "待付款",
"trigger": "用戶付款",
"destinationState": "待發貨"
},
{
"state": "待發貨",
"trigger": "發貨",
"destinationState": "待收貨"
},
{
"state": "待收貨",
"trigger": "確認收貨",
"destinationState": "已完成"
},
{
"state": "已完成",
"trigger": "評價",
"destinationState": "已評價"
},
{
"state": "已評價",
"trigger": "刪除",
"destinationState": "已刪除"
}
]
測試用例
/**
* 狀態從file中讀取
*/
@Test
public void stateFromDb() throws IOException {
String content = FileUtils.readToEnd(
StateMachineExample.class.getClassLoader().getResourceAsStream("stateless.json"),
Charset.defaultCharset());
StateMachineConfig<String, String> stateMachineConfig = new StateMachineConfig<>();
List<Map<String, String>> map = objectMapper.readValue(content, new TypeReference<List<Map<String, String>>>() {
});
map.forEach(o -> {
String state = o.get("state");
String trigger = o.get("trigger");
String destinationState = o.get("destinationState");
stateMachineConfig.configure(state).permit(trigger, destinationState);
});
StateMachine<String, String> stateMachine = new StateMachine<>("待收貨", stateMachineConfig);
log.info("當前狀態:{}", stateMachine.getState());
stateMachine.fire("確認收貨");
log.info("當前狀態:{}", stateMachine.getState());
}
結果

如果你的state和trigger不一致,比如狀態是待收獲,你的動作是評價,那狀態機就會報錯,狀態不能正確更新
