天天看點

設計模式 _第十四招式_狀态模式

一、定義

當一個對象内在狀态改變時允許其改變行為,這個對象看起來像改變了其類,狀态模式的核心是封裝,狀态的變更引起行為的變更,從外面看起來就像這個對象對應的類發生了改變一樣。

二、代碼示範

2.1 通用類圖

設計模式 _第十四招式_狀态模式

2.2 角色說明

  • State–抽象狀态角色

    接口或抽象類,負責對象狀态定義,并且封裝環境角色以實作狀态切換。

  • ConcreteSate–具體狀态角色

    每一個具體狀态必須要完成兩個職責:本狀态行為管理及趨向狀态處理,通俗的說就是本狀态要做的事情, 及如何過渡到其它狀态。

  • Context–環境角色

    定義用戶端需要的接口,并且負責到狀态的切換。

狀态模式相對比較複雜,它提供了一種對物質運動的一個觀察視角,通過狀态變更促使行為的變化,這類似水的狀态變更一樣。 一碗水初始狀态是液體,通過加熱轉換為氣态,狀态的改變引起了體積變大。這就是蒸汽機的原理。

2.3 抽象狀态角色

抽象狀态角色,聲明一個環境角色, 提供給各狀态類自行通路,并且提供了各個狀态的抽象行為。

package com.design.state.pattern;

/**
 * @description TODO
 * @date: 2019/9/21 23:09
 * @version: v 0.1
 */
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();
}

           

2.4 具體狀态角色

每一個具體狀态必須要完成兩個職責:本狀态行為管理及趨向狀态處理,通俗的說就是本狀态要做的事情, 及如何過渡到其它狀态。

package com.design.state.pattern;

/**
 * @description TODO
 * @date: 2019/9/21 23:13
 * @version: v 0.1
 */
public class ConcreteState1 extends State {
    @Override
    public void handle1() {
        System.out.println("ConcreteState1.handle1 TODO");
        //本狀态必須處理的邏輯
    }

    @Override
    public void handle2() {
        //設定目前狀态是state2
        super.context.setCurrentState(Context.STATE2);
        //過渡到state2狀态,有context實作
        super.context.handle2();
    }
}

           
package com.design.state.pattern;

/**
 * @description TODO
 * @date: 2019/9/21 23:13
 * @version: v 0.1
 */
public class ConcreteState2 extends State {
    @Override
    public void handle2() {
        System.out.println("ConcreteState1.handle2 TODO");
        //本狀态必須處理的邏輯
    }

    @Override
    public void handle1() {
        //設定目前狀态是state2
        super.context.setCurrentState(Context.STATE1);
        //過渡到state2狀态,有context實作
        super.context.handle1();
    }
}

           

2.5 環境角色

package com.design.state.pattern;

/**
 * @description TODO
 * @date: 2019/9/21 23:17
 * @version: v 0.1
 */
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();
    }
}

           

環境角色有兩個不成文的限制:

1)把狀态對象聲明為常量,有幾個狀态對象就聲明幾個靜态常量。

2)環境角色具有狀态抽象角色定義的所有行為,具體執行使用委托方式。

2.6 驗證場景類

package com.design.state.pattern;

/**
 * @description TODO
 * @date: 2019/9/21 23:09
 * @version: v 0.1
 */
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();
}

           

2.7 運作結果

ConcreteState1.handle1 TODO
ConcreteState2.handle2 TODO
           

三、優點

3.1 結構清晰

避免過多使用 switch…case或if…else 語句,避免了程式的複雜性,提高了可維護性。

3.2 遵循設計原則

提現了開閉原則和單一職責原則,每個狀态都是一個子類。

3.3 封閉性好

狀态變更是放在類的内部實作的, 外部調用不知道内部狀态變更邏輯。

四、缺點

可能會出現,子類太多導緻,類膨脹。

五、應用場景

  • 行為随狀态改變而改變的場景。
  • 條件、分支判斷的替代者,在程式中大量使用switch、if導緻邏輯混亂,使用狀态模式時,可以通過擴充子類實作條件的判斷處理。

六、注意事項

使用對象的狀态最好不要超過5個。

繼續閱讀