前言
我想大家平時都在開發重都遇見過屎山代碼,這些屎山代碼一般都是由于復雜且龐大的if-else造成的,狀態模式,是一種很好的優化屎山代碼的設計模式,本文將采用兩個業務場景的示例來講解如何使用狀態模式拯救屎山代碼。
目錄
前言
1.網購業務場景
1.1.需求
1.2.if else的實現
1.3.狀態模式的實現
2.電梯業務場景
2.1.需求
2.2.if else的實現
2.3.狀態模式的實現
1.網購業務場景
1.1.需求
我們來假設一個網購的業務場景,需求如下:
-
流程為付款、再發貨、在收貨,流程必須按照以上順序,也就是說發貨后不能支付、收貨后不能發貨和支付
-
付款后不能重復付款、發貨后不能重復發貨、收貨后不能重復收貨
1.2.if else的實現
這里我們設計一個Order訂單類,用int型的state來表示狀態,當然也可以用一個枚舉類來表示狀態會更規范一點,這里為了方便而已。
public class Order {//1 未付款//2 已付款//3 未發貨//4 已發貨//5 未收貨//6 已收貨private int state;
?public int getState() {return state;}
?public void setState(int state) {this.state = state;}
}
以收貨方法為例,業務邏輯實現出來會是:
public void receive(Order order){if(order.getState()==2){if(order.getState()==4){if(order.getState()==5){System.out.println("收貨成功");}else{System.out.println("已收貨,無法重復收貨");}}else{System.out.println("未發貨");}}else{System.out.println("未付款");}
}
可以看到一座小屎山代碼已經初具規模,但凡狀態再多一點、業務邏輯再復雜一點,這座屎山將會基本不具備可讀性。
1.3.狀態模式的實現
其實仔細觀察可以發現,很多時候狀態往往是和實體的行為是相關的。之所以引入狀態,我們是希望實體在不同的狀態時呈現出不同的行為。
以上面的場景為例,在支付狀態下,我們希望實體能呈現出支付相關的能力;在發貨狀態下呈現出發貨相關的能力;在收貨狀態下呈現出收貨相關的能力......
所以完全可以把狀態和能力封裝在一起,從而省掉外界的if-else判斷,這就是所謂的狀態模式。
狀態模式總結起來一句話:
實體在不同的狀態,擁有不同的行為。
作用是:
可以省掉大量判斷條件帶來的if-else邏輯分支,使得代碼更簡潔易讀。
接下來我們用狀態模式去改寫之前的代碼。
首先總結一下實體類會有的行為有哪些,其實就是付款、發貨、收貨,也就是三個方法,為了代碼的規范,可以抽象出行為接口,當然不抽象也可以,仁者見仁智者見智。
public interface OrderState{void pay(Order order);void ship(Order order);void receive(Order order);
}
接下來總結一下系統里面的狀態,訂單有三個維度的六種狀態,分別是:
付款狀態
未付款
已付款
發貨狀態
未發貨
已發貨
收貨狀態
未收貨
已收貨
于是可以得到有三個狀態實體。
將狀態和行為綁定,可以得到以下三個狀態實體。
支付狀態實體:
public class PayState implements OrderState{public void pay(Order order) {System.out.println("已支付,不能再次支付!");}
?public void ship(Order order) {order.setOrderState(new ShipState());System.out.println("已發貨!");}
?public void receive(Order order) {System.out.println("未發貨!不能收貨!");}
}
發貨狀態實體:
public class ShipState implements OrderState{public void pay(Order order) {System.out.println("已發貨!禁止重復支付!");}
?public void ship(Order order) {System.out.println("已經發貨!禁止重復支付");}
?public void receive(Order order) {order.setOrderState(new ReceiveState());System.out.println("收貨成功!");}
}
收貨狀態實體
public class ReceiveState implements OrderState{public void pay(Order order) {System.out.println("已收貨,不能再次支付!");}
?public void ship(Order order) {System.out.println("已收貨,不能再次發貨!");}
?public void receive(Order order) {System.out.println("已收貨,不能再次收貨!");}
}
測試代碼:
public class Test {public static void main(String[] args) {Order order=new Order();//初始狀態未待支付order.setOrderState(new PayState());order.pay();order.ship();order.receive();}
}
測試結果:
2.電梯業務場景
2.1.需求
我們考慮一個簡單的電梯系統,其中有以下狀態:
-
停止狀態(StoppedState): 當電梯處于停止狀態時,它可以接受移動到指定樓層的請求。
-
上升狀態(MovingState): 當電梯處于上升狀態時,它不能響應移動請求,因為它正在上升。
-
下降狀態(MovingState): 當電梯處于下降狀態時,它也不能響應移動請求,因為它正在下降。
規則:
-
當電梯處于停止狀態時,它可以接受移動到指定樓層的請求,并切換到移動狀態(上升或下降)。
-
當電梯處于上升狀態或下降狀態時,它不能接受移動請求,而是提示當前正在移動。
-
電梯在移動過程中不能響應其他移動請求,直到它到達指定樓層并切換到停止狀態。
在上面的業務情景中,我們通過使用狀態模式對電梯系統進行了優化。每個狀態(停止狀態和移動狀態)都對應一個狀態類,并定義了在該狀態下的行為。電梯狀態的切換由上下文類(ElevatorStateContext)來管理,它負責在不同狀態下執行不同的行為,并根據狀態的變化進行切換。通過使用狀態模式,我們將狀態切換邏輯封裝到不同的狀態類中,使代碼更加模塊化和可擴展。
2.2.if else的實現
class ElevatorIfElse {private String state = "停止";private int currentFloor = 1;
?public void setState(String newState) {state = newState;}
?public void moveToFloor(int floor) {if (state.equals("停止")) {System.out.println("電梯從 " + currentFloor + " 樓移動到 " + floor + " 樓");currentFloor = floor;} else if (state.equals("上升")) {System.out.println("電梯正在上升,不能移動");} else if (state.equals("下降")) {System.out.println("電梯正在下降,不能移動");}}
}
?
public class MainIfElse {public static void main(String[] args) {ElevatorIfElse elevator = new ElevatorIfElse();
?elevator.moveToFloor(5);elevator.setState("上升");elevator.moveToFloor(3);elevator.moveToFloor(7);elevator.setState("停止");elevator.moveToFloor(2);}
}
2.3.狀態模式的實現
interface ElevatorState {void moveToFloor(ElevatorStateContext context, int floor);
}
?
class StoppedState implements ElevatorState {@Overridepublic void moveToFloor(ElevatorStateContext context, int floor) {System.out.println("電梯從 " + context.getCurrentFloor() + " 樓移動到 " + floor + " 樓");context.setCurrentFloor(floor);context.setState(new MovingState());}
}
?
class MovingState implements ElevatorState {@Overridepublic void moveToFloor(ElevatorStateContext context, int floor) {System.out.println("電梯正在移動,不能移動");}
}
?
class ElevatorStateContext {private ElevatorState state;private int currentFloor = 1;
?public ElevatorStateContext() {this.state = new StoppedState();}
?public void setState(ElevatorState state) {this.state = state;}
?public void moveToFloor(int floor) {state.moveToFloor(this, floor);}
?public int getCurrentFloor() {return currentFloor;}
?public void setCurrentFloor(int currentFloor) {this.currentFloor = currentFloor;}
}
?
public class MainStatePattern {public static void main(String[] args) {ElevatorStateContext context = new ElevatorStateContext();
?context.moveToFloor(5);context.setState(new MovingState());context.moveToFloor(3);context.moveToFloor(7);context.setState(new StoppedState());context.moveToFloor(2);}
}