一、定義
狀态模式( State Pattern)也稱為狀态機模式( State Machine pattern),是允許對象在内部狀态發生改變時改變它的行為,對象看起來好像修改了它的類,屬于行為型模式。允許對象在内部狀态發生改變時改變它的行為,對象看起來好像修改了它的類狀态模式中類的行為是由狀态決定的,不同的狀态下有不同的行為。其意圖是讓一個對象在其内部改變的時候,其行為也随之改變。狀态模式核心是狀态與行為綁定,不同的狀态對應不同的行為。
狀态模式主要包含三種角色:
- 環境類角色( Context):定義用戶端需要的接口,内部維護一個目前狀态執行個體,并負責具體狀态的切換
- 抽象狀态角色( State):定義該狀态下的行為,可以有一個或多個行為;
- 具體狀态角色( Concretestate):具體實作該狀态對應的行為,并且在需要的情況下進行狀态切換

二、狀态模式的案例
比如訂單狀态的變化,稽核流程單子狀态的變化等等。在軟體開發過程中,對于某一項操作,可能存在不同的情況。通常處理方式就是使用 if.else或 switch. case條件語句進行枚舉。但是這種做法天然存在弊端:條件判斷語句過于臃腫,可讀性差,且不具備擴充性,維護難度也大,而如果轉換思維,将這些不同狀态獨立起來用各個不同的類進行表示,系統處于那種狀态,直接使用相應的狀态類對象進行處理,消除了 if. else, switch.ase等備援語句,代碼具有層次性且具備良好擴充力
狀态模式主要解決的就是當控制一個對象狀态的條件表達式過于複雜時得情況,通過把狀态的判斷邏輯轉移到表示不同狀态的一系列類中,可以把複雜的判斷邏輯簡單化。對象得行為依賴于它的狀态(屬性),并且會根據它的狀态改變而改變它的相關行為。狀态模式适用于以下場景:
- 行為随狀态改變而改變的場景
- 一個操作中含有龐大的多分支結構,并且這些分支取決于對象的狀态
1. Context類
環境角色具有兩個職責,即處理本狀态必須完成的任務,及決定是否可以過渡到其它狀态。對于環境角色,有幾個不成文的限制:
- 即把狀态對象聲明為靜态常量,有幾個狀态對象就聲明幾個狀态常量
- 環境角色具有狀态抽象角色定義的所有行為,具體執行使用委托方式
public class Context {
//定義狀态
public final static State STATE1 = new ConcreteState1();
public final static State STATE2 = new ConcreteState2();
//目前狀态
private State currentState;
//獲得目前狀态
public State getCurrentState() {
return currentState;
}
//設定目前狀态
public void setCurrentState(State currentState) {
this.currentState = currentState;
// System.out.println("目前狀态:" + currentState);
//切換狀态
this.currentState.setContext(this);
}
public void handle1() {
this.currentState.handle1();
}
public void handle2() {
this.currentState.handle2();
}
}
2. State抽象狀态類
抽象環境中聲明一個環境角色,提供各個狀态類自行通路,并且提供所有狀态的抽象行為,由各個實作類實作。
public abstract class State {
protected Context context;
public void setContext(Context context) {
this.context = context;
}
//行為1
public abstract void handle1();
//行為2
public abstract void handle2();
}
3. 具體狀态
具體狀态實作,這裡以定義ConcreteState1和ConcreteState2兩個具體狀态類為例,ConcreteState2的具體内容同ConcreteState1。
public class ConcreteState1 extends State {
@Override
public void handle1() {
//...
System.out.println("ConcreteState1 的 handle1 方法");
}
@Override
public void handle2() {
super.context.setCurrentState(Context.STATE2);
System.out.println("ConcreteState1 的 handle2 方法");
}
}
public class ConcreteState2 extends State {
@Override
public void handle1() {
//...
System.out.println("ConcreteState2 的 handle2 方法");
}
@Override
public void handle2() {
super.context.setCurrentState(Context.STATE1);
System.out.println("ConcreteState2的 handle2 方法");
}
}
4. Client用戶端
定義Context環境角色,初始化具體狀态1,執行行為觀察結果。
public class Client {
public static void main(String[] args) {
//定義環境角色
Context context = new Context();
//初始化狀态
context.setCurrentState(new ConcreteState1());
//行為執行
context.handle1();
context.handle2();
context.handle1();
context.handle2();
}
}
從運作結果可見,我們已經隐藏了狀态的變化過程,它的切換引起了行為的變化。對外來說,我們隻看到了行為的改變,而不用知道是狀态變化引起的。
三、總結
狀态模式與責任鍊模式:
狀态模式和責任鍊模式都能消除if分支過多的問題。但某些情況下,狀态模式中的狀态可以了解為責任,那麼這種情況下,兩種模式都可以使用從定義來看,狀态模式強調的是一個對象内在狀态的改變,而責任鍊模式強調的是外部節點對象間的改變。從其代碼實作上來看,他們間最大的差別就是狀态模式各個狀态對象知道自己下一個要進入的狀态對象;而責任鍊模式并不清楚其下一個節點處理對象,因為鍊式組裝由用戶端負責。
狀态模式與政策模式:
狀态模式和政策模式的UML類圖架構幾乎完全一樣, 但他們的應用場景是不一樣的。政策模式多種算法行為擇其一都能滿足,彼此之間是獨立的,使用者可自行更換政策算法;而狀态模式各個狀态間是存在互相關系的,彼此之間在一定條件下存在自動切換狀态效果,且使用者無法指定狀态,隻能設定初始狀态。
優點:
結構清晰:将狀态獨立為類, 消除了備援的if...else或switch...case語句, 使代碼更加簡潔,提高系統可維護性;
将狀态轉換顯示化:通常的對象内部都是使用數值類型來定義狀态,狀态的切換是通過指派進行表現,不夠直覺;而使用狀态類,在切換狀态時,是以不同的類進行表示,轉換目的更加明确;狀态類職責明确且具備擴充性。
缺點:
類膨脹:如果一個事物具備很多狀态,則會造成狀态類太多;
狀态模式的結構與實作都較為複雜,如果使用不當将導緻程式結構和代碼的混亂;
狀态模式對開閉原則的支援并不太好,對于可以切換狀态的狀态模式,增加新的狀态類需要修改那些負責狀态轉換的源代碼,否則無法切換到新增狀态,而且修改某個狀态類的行為也需
git源碼:https://gitee.com/TongHuaShuShuoWoDeJieJu/design_pattern.git
這短短的一生我們最終都會失去,不妨大膽一點,愛一個人,攀一座山,追一個夢