Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> java/android 設計模式學習筆記(19)---狀態模式

java/android 設計模式學習筆記(19)---狀態模式

編輯:關於Android編程

  這篇博客我們來介紹一下狀態模式(State Pattern),也是行為型設計模式之一。狀態模式的行為是由狀態來決定的,不同的狀態下有不同的行為。狀態模式和策略模式的結構類圖幾乎完全一樣,但它們的目的、本質卻完全不一樣。狀態模式的行為是平行的、不可替換的,策略模式的行為是彼此獨立、可相互替換的。狀態模式把對象的行為包裝在不同的狀態對象裡,每一個狀態對象都有一個共同的抽象狀態基類;而策略模式可以想象成是除了繼承之外的一種彈性替代方案,如果你使用繼承定義了一個類的行為,你將被這個行為困住,甚至要修改它都很難,有了策略模式,你可以通過組合不同的對象來改變行為。狀態模式的意圖是讓一個對象在其內部狀態發生改變的時候,其行為也隨之改變。

特點

  當一個對象的內在狀態改變時允許改變其行為,這個對象看起來像是改變了其類。
  狀態模式的使用場景:

一個對象的行為取決於它的狀態,並且它必須在運行時根據狀態改變它的行為;代碼中包含大量與狀態有關的條件語句,例如,一個操作中含有龐大的多分枝語句(if-else 或者 switch-case),且這些分支依賴於該對象的狀態。狀態模式將每一個條件分支放入一個獨立的類中,這使得你可以根據對象自身的情況將對象的狀態作為一個對象,這一對象可以不依賴於其他對象而獨立變化,這樣通過多態來去除過多的、重復的 if-else 等分支語句。

 

UML類圖

  這裡寫圖片描述vcfJq6O6PC9wPg0KQ29udGV4dKO6u7e+s8Dgo6y2qNLlv827p7jQ0MvIpLXEvdO/2qOszqy7pNK7uPYgU3RhdGUg19PA4KOs1eK49sq1wP22qNLlwcu21M/ztcS1scew17TMrKO7U3RhdGWjurPpz/PXtMyswOC78tXf17TMrL3Tv9qjrLao0uXSu7j2u/LV39K71+m907/ao6yx7cq+uMPXtMysz8K1xNDQzqqju0NvbmNyZXRlU3RhdGVBoaJDb25jcmV0ZVN0YXRlQqO6vt/M5de0zKzA4KOsw7/Su7j2vt/M5bXE17TMrMDgyrXP1rPpz/O1xCBTdGF0ZSDW0Lao0uW1xL3Tv9qjrLTTtvi077W9srvNrNe0zKzPwrXEsrvNrNDQzqqho6GhoaG+3bTLztLDx7/J0tTQtLP217TMrMSjyr21xM2o08O0+sLro7o8YnIgLz4NCte0zKy907/a0tS8sM/gudjX08Dgo7o8YnIgLz4NCjxzdHJvbmc+U3RhdGUuY2xhc3M8L3N0cm9uZz4NCjxwPiZuYnNwOzwvcD4NCjxwcmUgY2xhc3M9"brush:java;"> public interface State { void doSomething(); }

ConcreteStateA.class、ConcreteStateB.class、NullState.class

public class ConcreteStateA implements State {
    @Override
    public void doSomething() {
        System.out.print("this is ConcreteStateA's function\n");
    }
}
public class ConcreteStateB implements State{
    @Override
    public void doSomething() {
        System.out.print("this is ConcreteStateB's function\n");
    }
}
public class NullState implements State{
    @Override
    public void doSomething() {
        //do nothing
    }
}

Context類以及測試代碼:
Context.class

public class Context {
    private State state = new NullState();

    void setState(State state) {
        this.state = state;
    }

    void doSomething() {
        state.doSomething();
    }

    public static void main(String[] args) {
        Context context = new Context();
        context.setState(new ConcreteStateA());
        context.doSomething();
        context.setState(new ConcreteStateB());
        context.doSomething();
    }
}

最後結果:

this is ConcreteStateA's function
this is ConcreteStateB's function

示例與源碼

  在 Android 源碼中也有很多狀態模式的例子,MediaPlayer 和 WifiStateEngine 等,這裡我們來簡單看看 MediaPlayer 的狀態機:
  這裡寫圖片描述
橢圓代表 MediaPlayer 對象可能駐留的狀態。弧線表示驅動 MediaPlayer 在各個狀態之間遷移的播放控制操作。這裡有兩種類型的弧線。由一個箭頭開始的弧代表同步的方法調用,而以雙箭頭開頭的代表的弧線代表異步方法調用。MediaPlayer在這我就不詳細介紹了,網上資料很多,感興趣的可以去查閱一下。
  這裡再介紹一下狀態機,又稱為有限狀態自動機 (FSM:Finite State Machine),是表示有限多個狀態以及在這些狀態之間轉移和動作的數學模型。狀態存儲關於過去的信息,它反映從系統開始到現在時刻輸入的變化;轉移指示狀態變更,用必須滿足來確使轉移發生的條件來描述它;動作是在給定時刻要進行的活動描述,詳細的看看這篇博客:有限狀態機(FSM)的Java 演示 。
  實際 Android 開發過程中,我們一般會去根據實際情況去先構造一個狀態圖,定義每個狀態和每個狀態之間切換的事件,類似於上圖的 MediaPlayer,然後將該信息錄入進入狀態機,當目前的狀態接收到一個非法的跳轉事件時,可以拋出異常,這樣就能保證一切按照預先設定好的方向進行。

Demo

  我們這裡仍然以 wiki 上的 demo 為例,來實現一堆字符串的一個大小寫間隔打印:
Statelike.class

interface Statelike {
    void writeName(StateContext context, String name);
}

StateLowerCase.class 和 StateMultipleUpperCase.class

class StateLowerCase implements Statelike {
    @Override
    public void writeName(final StateContext context, final String name) {
        System.out.println(name.toLowerCase());
        context.setState(new StateMultipleUpperCase());
    }
}
class StateMultipleUpperCase implements Statelike {
    /** Counter local to this state */
    private int count = 0;

    @Override
    public void writeName(final StateContext context, final String name) {
        System.out.println(name.toUpperCase());
        /* Change state after StateMultipleUpperCase's writeName() gets invoked twice */
        if(++count > 1) {
            context.setState(new StateLowerCase());
        }
    }

}

StateContext.class

class StateContext {
    private Statelike myState;
    StateContext() {
        setState(new StateLowerCase());
    }

    /**
     * Setter method for the state.
     * Normally only called by classes implementing the State interface.
     * @param newState the new state of this context
     */
    void setState(final Statelike newState) {
        myState = newState;
    }

    public void writeName(final String name) {
        myState.writeName(this, name);
    }

    public static void main(String[] args) {
        final StateContext sc = new StateContext();

        sc.writeName("Monday");
        sc.writeName("Tuesday");
        sc.writeName("Wednesday");
        sc.writeName("Thursday");
        sc.writeName("Friday");
        sc.writeName("Saturday");
        sc.writeName("Sunday");
    }
}

最後結果:

monday
TUESDAY
WEDNESDAY
thursday
FRIDAY
SATURDAY
sunday

例子也很簡單,一目了然。

總結

  狀態模式的關鍵點在於不同的狀態下對於統一行為有不同的響應,這其實就是一個將 if-else 用多態來實現的一個具體實例。在 if-else 或者 switch-case 形勢下根據不同的狀態進行判斷,如果是狀態 A 那麼執行方法 A,狀態 B 執行方法 B,但這種實現使得邏輯耦合在一起,易於出錯不易維護,通過狀態模式能夠很好的消除這類“丑陋”的邏輯處理,當然並不是任何出現 if-else 的地方都應該通過狀態模式重構,模式的運用一定要考慮所處的情景以及你要解決的問題,只有符合特定的場景才建議使用對應的模式。和程序狀態機(PSM)不同,狀態模式用類代表狀態,狀態的轉換可以由 State 類或者 Context 類控制。
  優點:

通過將每個狀態封裝進一個類,將以後所做的修改局部化;將所有與一個特定狀態相關的行為封裝到一個對象中,繁瑣的狀態判斷轉換成結構清晰的狀態類族,在避免代碼膨脹的同時增加可維護性和可擴展性。缺點當然也很明顯,也是絕大部分設計模式的通病,類數目的增多。

源碼下載

  https://github.com/zhaozepeng/Design-Patterns/tree/master/StatePattern

 
  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved