欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

詳解Java中三種狀態(tài)機實現(xiàn)方式來優(yōu)雅消滅 if-else 嵌套

 更新時間:2025年08月14日 08:38:08   作者:Micro麥可樂  
這篇文章主要為大家詳細介紹了Java中三種狀態(tài)機實現(xiàn)方式從而優(yōu)雅消滅 if-else 嵌套,文中的示例代碼講解詳細,感興趣的小伙伴可以跟隨小編一起學習一下

1. 前言

在博主之前 【設(shè)計模式】的專欄中,介紹過一個狀態(tài)模式(津津樂道設(shè)計模式 - 狀態(tài)模式詳解),并以交通信號燈的實現(xiàn)進行狀態(tài)模式的演示講解,實際上狀態(tài)模式也特別適合處理那些包含大量條件語句(如if-else或switch)的復雜狀態(tài)轉(zhuǎn)換邏輯。

為什么使用狀態(tài)模式消除if-else?

在日常 Java 開發(fā)中,我們常常遇到這樣的情況:

  • 不同的狀態(tài)有不同的處理邏輯
  • 狀態(tài)之間會相互切換
  • 不同狀態(tài)下執(zhí)行的動作可能完全不同

這時,如果我們用 if-elseswitch-case 來寫,代碼很容易變得臃腫難維護:比如下面代碼

if (status == 0) {
    // 待支付邏輯
} else if (status == 1) {
    // 已支付邏輯
} else if (status == 2) {
    // 已發(fā)貨邏輯
} else if (status == 3) {
    // 已收貨邏輯
}

這種寫法的問題:

邏輯分支多,擴展性差

新增狀態(tài)時,需要修改原有代碼(違反 開閉原則)

狀態(tài)切換邏輯容易分散在各個 if-else 中,不夠集中

那么使用狀態(tài)機(State Machine)也可稱狀態(tài)模式,就可以解決上述這些問題,并具備以下優(yōu)點:

  • 消除復雜的條件判斷語句
  • 提高代碼可讀性和可維護性
  • 使狀態(tài)轉(zhuǎn)換邏輯更加清晰
  • 符合開閉原則,易于擴展新狀態(tài)

2. 復現(xiàn)傳統(tǒng)if-else實現(xiàn)的業(yè)務場景問題

假設(shè)有一個電商訂單系統(tǒng),訂單狀態(tài)有:

  • 待支付(PendingPay)
  • 已支付(Paid)
  • 已發(fā)貨(Shipped)
  • 已完成(Completed)

訂單可以:

  • 從待支付 → 支付 → 發(fā)貨 → 完成
  • 取消訂單(在待支付狀態(tài)下)

那么可能你的代碼就是像這樣的:

public class OrderServiceIfElse {
    public void handle(int status, String action) {
        if (status == 0) {
            if ("pay".equals(action)) {
                System.out.println("訂單已支付");
            } else if ("cancel".equals(action)) {
                System.out.println("訂單已取消");
            }
        } else if (status == 1) {
            if ("ship".equals(action)) {
                System.out.println("訂單已發(fā)貨");
            }
        } else if (status == 2) {
            if ("confirm".equals(action)) {
                System.out.println("訂單已完成");
            }
        }
    }
}

又或者是這樣的:

public class Order {
    private String state;
   
    public void process() {
        if ("NEW".equals(state)) {
            System.out.println("處理新訂單");
            state = "PROCESSING";
        } else if ("PROCESSING".equals(state)) {
            System.out.println("訂單處理中");
            state = "SHIPPED";
        } else if ("SHIPPED".equals(state)) {
            System.out.println("訂單已發(fā)貨");
            state = "DELIVERED";
        } else if ("DELIVERED".equals(state)) {
            System.out.println("訂單已完成");
        } else {
            throw new IllegalStateException("無效訂單狀態(tài): " + state);
        }
    }
}

無論是哪一種寫法,都會存在以下問題:

當狀態(tài)增多時,代碼變得臃腫難以維護

違反開閉原則,添加新狀態(tài)需要修改現(xiàn)有代碼

狀態(tài)轉(zhuǎn)換邏輯分散在多個地方

難以跟蹤狀態(tài)轉(zhuǎn)換規(guī)則

3. 用狀態(tài)機模式改造

下面我們使用狀態(tài)模式重構(gòu)上述訂單處理流程:

3.1 定義狀態(tài)接口

public interface OrderState {
    void pay(OrderContext context);
    void ship(OrderContext context);
    void confirm(OrderContext context);
    void cancel(OrderContext context);
}

3.2 創(chuàng)建上下文類

public class OrderContext {
    private OrderState state;

    public OrderContext(OrderState state) {
        this.state = state;
    }

    public void setState(OrderState state) {
        this.state = state;
    }

    public void pay() {
        state.pay(this);
    }

    public void ship() {
        state.ship(this);
    }

    public void confirm() {
        state.confirm(this);
    }

    public void cancel() {
        state.cancel(this);
    }
}

3.3 定義具體狀態(tài)類

// 待支付
public class PendingPayState implements OrderState {
    @Override
    public void pay(OrderContext context) {
        System.out.println("訂單支付成功");
        context.setState(new PaidState());
    }

    @Override
    public void ship(OrderContext context) {
        System.out.println("請先支付訂單");
    }

    @Override
    public void confirm(OrderContext context) {
        System.out.println("請先支付訂單");
    }

    @Override
    public void cancel(OrderContext context) {
        System.out.println("訂單已取消");
    }
}

// 已支付
public class PaidState implements OrderState {
    @Override
    public void pay(OrderContext context) {
        System.out.println("訂單已支付,請勿重復支付");
    }

    @Override
    public void ship(OrderContext context) {
        System.out.println("訂單已發(fā)貨");
        context.setState(new ShippedState());
    }

    @Override
    public void confirm(OrderContext context) {
        System.out.println("訂單還未發(fā)貨");
    }

    @Override
    public void cancel(OrderContext context) {
        System.out.println("已支付訂單不能取消");
    }
}

// 已發(fā)貨
public class ShippedState implements OrderState {
    @Override
    public void pay(OrderContext context) {
        System.out.println("訂單已支付");
    }

    @Override
    public void ship(OrderContext context) {
        System.out.println("訂單已經(jīng)發(fā)貨");
    }

    @Override
    public void confirm(OrderContext context) {
        System.out.println("訂單已完成");
        context.setState(new CompletedState());
    }

    @Override
    public void cancel(OrderContext context) {
        System.out.println("發(fā)貨后不能取消訂單");
    }
}

// 已完成
public class CompletedState implements OrderState {
    @Override
    public void pay(OrderContext context) {
        System.out.println("訂單已完成,無法支付");
    }

    @Override
    public void ship(OrderContext context) {
        System.out.println("訂單已完成,無法發(fā)貨");
    }

    @Override
    public void confirm(OrderContext context) {
        System.out.println("訂單已完成");
    }

    @Override
    public void cancel(OrderContext context) {
        System.out.println("訂單已完成,無法取消");
    }
}

3.4 測試使用

public class StateMachineTest {
    public static void main(String[] args) {
        // 初始狀態(tài):待支付
        OrderContext order = new OrderContext(new PendingPayState());

        order.pay();     // 支付
        order.ship();    // 發(fā)貨
        order.confirm(); // 確認收貨

		//分別輸出
		//訂單支付成功
		//訂單已發(fā)貨
		//訂單已完成
    }
}

4. 枚舉 + Map的輕量狀態(tài)機實現(xiàn)

這里博主再升級一下使用枚舉 + Map 的輕量狀態(tài)機實現(xiàn),這種寫法相比經(jīng)典狀態(tài)模式,代碼量更少,適合狀態(tài)數(shù)不多、且狀態(tài)邏輯相對簡單的場景

這種寫法的核心思想是:

用枚舉類定義所有狀態(tài)

每個狀態(tài)實現(xiàn)自己的行為邏輯

通過 Map 注冊狀態(tài)與處理邏輯的映射關(guān)系

直接通過當前狀態(tài)對象來執(zhí)行對應方法,避免 if-else

4.1 定義狀態(tài)枚舉

public enum OrderStateEnum {
    PENDING_PAY {
        @Override
        public OrderStateEnum pay() {
            System.out.println("訂單支付成功");
            return PAID;
        }

        @Override
        public OrderStateEnum ship() {
            System.out.println("請先支付訂單");
            return this;
        }

        @Override
        public OrderStateEnum confirm() {
            System.out.println("請先支付訂單");
            return this;
        }

        @Override
        public OrderStateEnum cancel() {
            System.out.println("訂單已取消");
            return this;
        }
    },
    PAID {
        @Override
        public OrderStateEnum pay() {
            System.out.println("訂單已支付,請勿重復支付");
            return this;
        }

        @Override
        public OrderStateEnum ship() {
            System.out.println("訂單已發(fā)貨");
            return SHIPPED;
        }

        @Override
        public OrderStateEnum confirm() {
            System.out.println("訂單還未發(fā)貨");
            return this;
        }

        @Override
        public OrderStateEnum cancel() {
            System.out.println("已支付訂單不能取消");
            return this;
        }
    },
    SHIPPED {
        @Override
        public OrderStateEnum pay() {
            System.out.println("訂單已支付");
            return this;
        }

        @Override
        public OrderStateEnum ship() {
            System.out.println("訂單已經(jīng)發(fā)貨");
            return this;
        }

        @Override
        public OrderStateEnum confirm() {
            System.out.println("訂單已完成");
            return COMPLETED;
        }

        @Override
        public OrderStateEnum cancel() {
            System.out.println("發(fā)貨后不能取消訂單");
            return this;
        }
    },
    COMPLETED {
        @Override
        public OrderStateEnum pay() {
            System.out.println("訂單已完成,無法支付");
            return this;
        }

        @Override
        public OrderStateEnum ship() {
            System.out.println("訂單已完成,無法發(fā)貨");
            return this;
        }

        @Override
        public OrderStateEnum confirm() {
            System.out.println("訂單已完成");
            return this;
        }

        @Override
        public OrderStateEnum cancel() {
            System.out.println("訂單已完成,無法取消");
            return this;
        }
    };

    public abstract OrderStateEnum pay();
    public abstract OrderStateEnum ship();
    public abstract OrderStateEnum confirm();
    public abstract OrderStateEnum cancel();
}

這里的設(shè)計是:

每個狀態(tài)用一個枚舉常量表示

每個枚舉常量實現(xiàn)自己的狀態(tài)切換邏輯

方法返回新的狀態(tài)枚舉,實現(xiàn)狀態(tài)流轉(zhuǎn)

4.2 配置上下文類

public class OrderContextEnum {
    private OrderStateEnum state;

    public OrderContextEnum(OrderStateEnum state) {
        this.state = state;
    }

    public void pay() {
        state = state.pay();
    }

    public void ship() {
        state = state.ship();
    }

    public void confirm() {
        state = state.confirm();
    }

    public void cancel() {
        state = state.cancel();
    }
}

4.3 測試使用

public class EnumStateMachineTest {
    public static void main(String[] args) {
        OrderContextEnum order = new OrderContextEnum(OrderStateEnum.PENDING_PAY);

        order.pay();     // 支付
        order.ship();    // 發(fā)貨
        order.confirm(); // 確認收貨
    }
}

5. 使用 Spring StateMachine 實現(xiàn)訂單狀態(tài)機

Spring StateMachineSpring 官方提供的狀態(tài)機框架,支持可配置狀態(tài)流轉(zhuǎn)、事件驅(qū)動、監(jiān)聽器回調(diào)等功能,特別適合業(yè)務流程復雜、狀態(tài)多變的場景。

5.1 依賴引入

<dependency>
    <groupId>org.springframework.statemachine</groupId>
    <artifactId>spring-statemachine-core</artifactId>
    <version>3.2.1</version>
</dependency>

5.2 定義狀態(tài)與事件枚舉

// 訂單狀態(tài)
public enum OrderState {
    PENDING_PAY, // 待支付
    PAID,        // 已支付
    SHIPPED,     // 已發(fā)貨
    COMPLETED    // 已完成
}

// 觸發(fā)事件
public enum OrderEvent {
    PAY,         // 支付
    SHIP,        // 發(fā)貨
    CONFIRM,     // 確認收貨
    CANCEL       // 取消訂單
}

5.3 配置狀態(tài)機

import org.springframework.context.annotation.Configuration;
import org.springframework.statemachine.config.EnableStateMachine;
import org.springframework.statemachine.config.EnumStateMachineConfigurerAdapter;
import org.springframework.statemachine.config.builders.StateMachineStateConfigurer;
import org.springframework.statemachine.config.builders.StateMachineTransitionConfigurer;
import org.springframework.statemachine.config.builders.StateMachineConfigurationConfigurer;
import org.springframework.statemachine.listener.StateMachineListenerAdapter;
import org.springframework.statemachine.state.State;

import java.util.EnumSet;

@Configuration
@EnableStateMachine
public class OrderStateMachineConfig extends EnumStateMachineConfigurerAdapter<OrderState, OrderEvent> {

    @Override
    public void configure(StateMachineStateConfigurer<OrderState, OrderEvent> states) throws Exception {
        states
            .withStates()
            .initial(OrderState.PENDING_PAY)  // 初始狀態(tài)
            .states(EnumSet.allOf(OrderState.class)); // 所有狀態(tài)
    }

    @Override
    public void configure(StateMachineTransitionConfigurer<OrderState, OrderEvent> transitions) throws Exception {
        transitions
            .withExternal()
                .source(OrderState.PENDING_PAY).target(OrderState.PAID).event(OrderEvent.PAY)
            .and()
            .withExternal()
                .source(OrderState.PAID).target(OrderState.SHIPPED).event(OrderEvent.SHIP)
            .and()
            .withExternal()
                .source(OrderState.SHIPPED).target(OrderState.COMPLETED).event(OrderEvent.CONFIRM)
            .and()
            .withExternal()
                .source(OrderState.PENDING_PAY).target(OrderState.PENDING_PAY).event(OrderEvent.CANCEL);
    }

    @Override
    public void configure(StateMachineConfigurationConfigurer<OrderState, OrderEvent> config) throws Exception {
        config
            .withConfiguration()
            .listener(new StateMachineListenerAdapter<>() {
                @Override
                public void stateChanged(State<OrderState, OrderEvent> from, State<OrderState, OrderEvent> to) {
                    System.out.println("狀態(tài)切換: " 
                        + (from == null ? "無" : from.getId()) 
                        + " -> " + to.getId());
                }
            });
    }
}

5.4 測試代碼

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.statemachine.StateMachine;
import org.springframework.stereotype.Component;

@Component
public class OrderStateMachineTest implements CommandLineRunner {

    @Autowired
    private StateMachine<OrderState, OrderEvent> stateMachine;

    @Override
    public void run(String... args) throws Exception {
        stateMachine.start();

        stateMachine.sendEvent(OrderEvent.PAY);
        stateMachine.sendEvent(OrderEvent.SHIP);
        stateMachine.sendEvent(OrderEvent.CONFIRM);

        stateMachine.stop();
    }
}

觀察控制臺會輸出如下:

狀態(tài)切換: 無 -> PENDING_PAY
狀態(tài)切換: PENDING_PAY -> PAID
狀態(tài)切換: PAID -> SHIPPED
狀態(tài)切換: SHIPPED -> COMPLETED

6. 對比三種方案

實現(xiàn)方式優(yōu)點缺點適用場景
經(jīng)典狀態(tài)模式結(jié)構(gòu)清晰,面向?qū)ο?/td>類文件多,狀態(tài)多時管理復雜狀態(tài)多、邏輯復雜的 OO 場景
枚舉狀態(tài)機簡潔,集中管理狀態(tài)多時枚舉類太長狀態(tài)少、邏輯簡單
Spring StateMachine功能強大,可配置化需要額外依賴,學習成本高大型系統(tǒng)、狀態(tài)規(guī)則經(jīng)常變動

經(jīng)典狀態(tài)模式適合復雜業(yè)務流程,易于模塊化管理

枚舉 + Map 注冊或枚舉直接實現(xiàn)行為,適合小型項目或簡單狀態(tài)流轉(zhuǎn)

在 Java 中,枚舉天生是單例的,用它實現(xiàn)狀態(tài)機既簡潔又線程安全

7. 總結(jié)

本文博主詳細介紹了使用狀態(tài)模式消除if-else, 通過經(jīng)典狀態(tài)模式、枚舉狀態(tài)機、Spring StateMachine 三種方式 ,從純手寫模式 → 枚舉模式 → 框架模式的完整對比,進行了相關(guān)代碼演示。當小伙伴們發(fā)現(xiàn)自己在編寫大量條件語句來處理對象狀態(tài)時,考慮使用狀態(tài)模式重構(gòu)您的代碼。

到此這篇關(guān)于詳解Java中三種狀態(tài)機實現(xiàn)方式來優(yōu)雅消滅 if-else 嵌套的文章就介紹到這了,更多相關(guān)Java狀態(tài)機內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評論