1. 程式人生 > >設計模式系列之二十一:狀態模式

設計模式系列之二十一:狀態模式

1.定義

當一個物件內在狀態改變時允許其改變行為,這個物件看起來像改變了其類。

2.通用類圖

角色介紹

  • State 抽象狀態角色:介面或抽象類,負責物件狀態定義,並且封裝環境角色以實現狀態切換
  • ConcreteState 具體狀態角色:每一個具體狀態必須完成兩個職責:本狀態的行為管理以及趨向狀態處理,通俗地講,就是本狀態下要做的事情,以及本狀態如何過度到其他狀態
  • Context 環境角色:定義客戶端需要的介面,並且負責具體狀態的切換

3.通用原始碼

抽象狀態角色

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(); }

抽象狀態中宣告一個環境角色,提供各個狀態類自行訪問,並且提供所有狀態的抽象行為,由各個實現類實現
具體狀態角色

public class ConcreteState1
extends State{
@Override public void handle1() { //本狀態下必須處理的邏輯 } @Override public void handle2() { //設定當前狀態為stat2 super.context.setCurrentState(Context.STATE2); //過渡到state2,由Context實現 super.context.handle2(); } }
public class ConcreteState2
extends State {
@Override public void handle1() { //設定當前狀態為狀態1 super.context.setCurrentState(Context.STATE1); //過渡到state1狀態,由context實現 super.context.handle1(); } @Override public void handle2() { //本狀態下必須要處理的邏輯 } }

具體狀態角色有兩個職責:處理本狀態必須完成的任務,決定是否可以過渡到其他狀態。
具體環境角色

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;
        //切換狀態
        this.currentState.setContext(this);
    }
    //行為委託
    public void handle1() {
        this.currentState.handle1();
    }
    public void handle2() {
        this.currentState.handle2();
    }
}

環境角色有兩個不成文的約束:

  • 把狀態物件宣告為靜態常量,有幾個狀態物件就宣告幾個靜態常量
  • 環境角色具有狀態抽象角色定義的所有行為,具體執行使用委託方式

4.Demo

電梯是社會發展不可或缺的部分,電梯有開門、關門、執行、停止這幾個狀態。
但是電梯的每一個狀態都是有條件:

  • 敞門狀態:按了電梯上下按鈕,門會開,在這個狀態下,電梯能做的只能是關門
  • 閉門狀態:在此狀態下,只能是開門,停止,執行
  • 執行狀態:在此狀態下,只能做停止。
  • 停止狀態:這時,電梯可以繼續執行,也可以開門

    這個時候如果用switch迴圈去判斷,可想而知邏輯有多雜亂。這還是正常情況,如果電梯出故障了呢,它在執行狀態時就不能做停止和開門操作。還要電梯維修的時候可以不開門,你也不能讓維修人修著修著電梯跑了不是。這樣你又要加多少判斷。這個時候引入狀態模式,就可以很方便地解決這個問題。

    具體程式碼,下次貼出。

5.優缺點

  • 優點
    1. 結構清晰
      • 避免了過多的switch…case或者if…else語句,提高了系統的可維護性
    2. 遵循設計原則
      • 遵循了開閉原則和單一職責原則
    3. 封裝性非常好
      • 狀態變換放置到類的內部實現,外部的呼叫不用知道類內部如何實現狀態和行為的切換
  • 缺點
    • 子類太多,會造成類膨脹。解決問題的辦法不止一種,我們也可以在資料庫建立一個狀態表,然後根據狀態執行響應的操作。

6.應用場景

  • 行為隨狀態改變而改變的場景
    • 這也是狀態模式的出發點,例如許可權設計,人員的不同狀態即使執行相同的行為結果也會不同
  • 條件、分支判斷語句的替代者
    • 程式中大量使用switch語句或者if語句導致 程式結構不清晰,邏輯混亂。
  • 注意:
    • 使用狀態模式時物件的狀態最好不超過5個