Android狀態(tài)模式的幾種應用場景

最近事情太多,好久沒寫博客了, 想來之前的設計模式系列還有好幾種設計模式?jīng)]說, 正好最近寫代碼用了狀態(tài)模式, 于是便有了這篇文章.

  • 前言

在平時開發(fā)中,我們的某個對象可能有很多種狀態(tài),若不用狀態(tài)模式,我們平時的"殺手锏"是if判斷, 大量的if判斷, 是什么情況干什么事情.

在這種情況下,每多一種狀態(tài),將會使得代碼要做各種修改,并且要小心翼翼是考慮各個狀態(tài)不能亂掉, 以及各狀態(tài)切換的事情.

那么這種情況下, 我們就可以考慮狀態(tài)模式.

  • 定義

狀態(tài)模式把所研究的對象的行為包裝在不同的狀態(tài)對象里,每一個狀態(tài)對象都屬于一個抽象狀態(tài)類的一個子類。狀態(tài)模式的意圖是讓一個對象在其內(nèi)部狀態(tài)改變的時候眶蕉,其行為也隨之改變荣堰。

  • 簡單實踐-enum類實現(xiàn)

對于UI在不同狀態(tài)的改變,可以用狀態(tài)模式解決.假設一個情況:你有4個UI模式, 分別是登錄前,登錄中,登錄失敗,登錄成功.四個模式中背景圖和標題都會改變,此時不如試試枚舉(即將UI id分裝一個類):

我們可以寫成這樣

private LogState state;
public enum LogState {

    LOGGING(R.color.colorPrimaryDark,
            R.string.app_name),

    LOGGING1(R.color.colorPrimary,
            R.string.app_name),

    LOGGING3(R.color.colorPrimaryDark,
             R.string.app_name),

    LOGGING4(R.color.colorPrimary,
             R.string.app_name);

    public final int backgroundID;
    public final int titleID;

    LogState(int backgroundID, int titleID) {
        this.backgroundID = backgroundID;
        this.titleID = titleID;
    }
}

此時用一個變量state,去記錄當前的狀態(tài),而更新UI部分,背景永遠是

bg.setBackgroundResource(state.backgroundID);
title.setText(getString(state.titleID));

此時狀態(tài)與UI的更新耦合度也沒有了. UI只負責設置背景和文字,而我們自己負責改變狀態(tài)即可.而實際情況中, 我們的state日會有各種操作, 我們的UI有各種模式, 都可以這樣. 不過.Google不建議這么使用, 因為枚舉編譯完占了太多內(nèi)存了.不過上面的情況還好了.

  • 普通實踐-抽象出的狀態(tài)模式

這種用法有點像策略模式,即有一個抽象類,或者是接口.每個狀態(tài)有其不同的實現(xiàn). 父類通過多態(tài),通過賦值不同的子類來實現(xiàn)狀態(tài)模式的狀態(tài)切換.

舉個遙控器列子:
遙控器有開關機的狀態(tài).那我們有兩個實現(xiàn),一個開機的實現(xiàn),一個關機的實現(xiàn)類.他們都繼承一個 press接口. 完成里面的onPressed方法.

Press mControl;

class OffControl implements Press{

    @Override
    public void onPressed() {
        Log.d(TAG, "onPressed: 開機");
    }
}

class OnControl implements Press{

    @Override
    public void onPressed() {
        Log.d(TAG, "onPressed: 關機");
    }
}

即,當mControl為OnControl狀態(tài)時,按下就會關機, 當為OffControl時,按下即會開機.

顯然,實際情況下我們的遙控器會有很多功能,這樣在開關機甚至待機等各種狀態(tài)下完成不同實現(xiàn),即可很好的管理狀態(tài).什么狀態(tài)該干什么事情,而避免大量的if else

  • 神級實踐-StateMachine

位于:package com.android.internal.util;

這是Android源碼中的一個分層狀態(tài)機匙铡,非常強大, 可惜沒有向外開放, 不在AndroidSDK里面

其可以處理各種State類的轉(zhuǎn)化蒋搜。State狀態(tài)類必須實現(xiàn)processMessage方法,為了創(chuàng)建/摧毀工作環(huán)境所灸,還可以繼承實現(xiàn)enter/exit等方法荧琼。

StateMachine可以在每一個狀態(tài)內(nèi)譬胎,定義其接收不同的指令,會切換到哪個狀態(tài)命锄,而不需要狀態(tài)機主動去設定狀態(tài)堰乔,降低了主體和狀態(tài)之間的耦合,增加一個新狀態(tài)時更加方便脐恩。

其主要方法有:

addState(State state) //增加狀態(tài)
addState(State state, State parent)   //增加狀態(tài), 并且告訴狀態(tài)機后者為父狀態(tài)
setInitialState(State initialState)  //設置初始狀態(tài)
sendMessage(int what)                //發(fā)送消息,消息由子狀態(tài)processMsg處理,若沒有子狀態(tài)處理,則調(diào)用父狀態(tài)處理.
transitionTo(IState destState)       //變換狀態(tài)

transitionTo詳解:

mP0
/   \
mP1   mS0
/   \
mS2   mS1
 /  \    \
mS3  mS4  mS5  ---> 初始狀態(tài)

假設初始狀態(tài)mS5镐侯,各個父狀態(tài)同樣也是活動的,于是mP0, mP1, mS1 和mS5都是活動的驶冒。當有一個消息發(fā)出來苟翻,就會依次調(diào)用mS5,
mS1, mP1, mP0的processMessage方法(前提是都會返回false或者NOT_HANDLED)。

假設mS5的processMessage可以處理這個消息骗污,并且會調(diào)用transitionTo(mS4)將狀態(tài)轉(zhuǎn)為mS4崇猫,然后返回true 或 HANDLED。processMessage返回后會進入performTransitions方法需忿,其會找到mS5和mS4的共同父狀態(tài)诅炉,也就是mP1蜡歹。緊接著會依次調(diào)用mS5.exit, mS1.exit 然后是 mS2.enter mS4.enter. 這時mP0, mP1, mS2,mS4 這四個狀態(tài)是活動的涕烧,當下一個消息到來的時候季稳,就會激活mS4.processMessage方法。

使用該狀態(tài)機可以很好的實現(xiàn)各個狀態(tài)之間的切換.

該狀態(tài)機的使用demo見 frameworks/base/core/java/com/android/internal/util/StateMachine.java 類的注釋.有興趣的可以看看.


本文作者:Anderson/Jerey_Jobs

博客地址 : http://jerey.cn/

簡書地址 : Anderson大碼渣

github地址 : https://github.com/Jerey-Jobs

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末澈魄,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子仲翎,更是在濱河造成了極大的恐慌痹扇,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,311評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件溯香,死亡現(xiàn)場離奇詭異鲫构,居然都是意外死亡,警方通過查閱死者的電腦和手機玫坛,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評論 2 382
  • 文/潘曉璐 我一進店門结笨,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人湿镀,你說我怎么就攤上這事炕吸。” “怎么了勉痴?”我有些...
    開封第一講書人閱讀 152,671評論 0 342
  • 文/不壞的土叔 我叫張陵赫模,是天一觀的道長。 經(jīng)常有香客問我蒸矛,道長瀑罗,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,252評論 1 279
  • 正文 為了忘掉前任雏掠,我火速辦了婚禮斩祭,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘乡话。我一直安慰自己摧玫,他們只是感情好,可當我...
    茶點故事閱讀 64,253評論 5 371
  • 文/花漫 我一把揭開白布蚊伞。 她就那樣靜靜地躺著席赂,像睡著了一般。 火紅的嫁衣襯著肌膚如雪时迫。 梳的紋絲不亂的頭發(fā)上颅停,一...
    開封第一講書人閱讀 49,031評論 1 285
  • 那天,我揣著相機與錄音掠拳,去河邊找鬼癞揉。 笑死,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的喊熟。 我是一名探鬼主播柏肪,決...
    沈念sama閱讀 38,340評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼芥牌!你這毒婦竟也來了烦味?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,973評論 0 259
  • 序言:老撾萬榮一對情侶失蹤壁拉,失蹤者是張志新(化名)和其女友劉穎谬俄,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體弃理,經(jīng)...
    沈念sama閱讀 43,466評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡溃论,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,937評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了痘昌。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片钥勋。...
    茶點故事閱讀 38,039評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖辆苔,靈堂內(nèi)的尸體忽然破棺而出算灸,到底是詐尸還是另有隱情,我是刑警寧澤姑子,帶...
    沈念sama閱讀 33,701評論 4 323
  • 正文 年R本政府宣布乎婿,位于F島的核電站,受9級特大地震影響街佑,放射性物質(zhì)發(fā)生泄漏谢翎。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,254評論 3 307
  • 文/蒙蒙 一沐旨、第九天 我趴在偏房一處隱蔽的房頂上張望森逮。 院中可真熱鬧,春花似錦磁携、人聲如沸褒侧。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽闷供。三九已至,卻和暖如春统诺,著一層夾襖步出監(jiān)牢的瞬間歪脏,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工粮呢, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留婿失,地道東北人钞艇。 一個月前我還...
    沈念sama閱讀 45,497評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像豪硅,于是被迫代替她去往敵國和親哩照。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 42,786評論 2 345

推薦閱讀更多精彩內(nèi)容