隨時(shí)靈活變化-狀態(tài)模式

模式介紹

狀態(tài)模式的結(jié)構(gòu)和策略模式幾乎一模一樣。

但是它們兩者的目的、本質(zhì)卻完全不同。

策略模式的行為是彼此獨(dú)立,相互替換的?;叵胫芭e的價(jià)格計(jì)算器,我們出行時(shí)想使用地鐵,則使用地鐵的價(jià)格計(jì)算器,如果使用出租車,則使用出租車的價(jià)格計(jì)算器......

狀態(tài)模式的行為則是平行的,不可替換的。狀態(tài)模式更像是被封裝在對象內(nèi)部的一個(gè)東西,當(dāng)對象的狀態(tài)發(fā)生變化時(shí),其行為也要發(fā)生變化。

使用場景

  • 一個(gè)對象的行為需要根據(jù)狀態(tài)發(fā)生變化,尤其是在運(yùn)行時(shí)狀態(tài)發(fā)生變化,行為需要跟著一起變化時(shí);
  • 代碼中有大量判斷語句(if、switch),且這些語句依賴該對象的狀態(tài)。

模式角色

  • State:狀態(tài)接口,定義所有行為的抽象。
  • ConcreteStateA、ConcreteStateB:某個(gè)狀態(tài)的具體行為實(shí)現(xiàn),一個(gè)狀態(tài)對應(yīng)一個(gè)具體行為實(shí)現(xiàn)。

模式示例

相信大家在開發(fā)中,只要是動態(tài)App(和服務(wù)器有交互),都會有登錄的需求。

針對這個(gè)需求,我們可以得出兩個(gè)狀態(tài):登錄狀態(tài)、未登錄狀態(tài)。

接著我們可以想象一些行為:

  • 登錄
  • 退出登錄
  • 查看賬戶金幣
  • 賺取金幣
  • 金幣兌換道具

針對上述行為,在登錄狀態(tài)和未登錄狀態(tài)下,所做的事情是完全不同的:

  1. 登錄狀態(tài):
    • 登錄:提示用戶已經(jīng)登錄過了,請勿重復(fù)登錄
    • 退出登錄:清除用戶緩存并提示用戶退出登錄成功
    • 查看賬戶金幣:從服務(wù)器查詢用戶余額
    • 賺取金幣:跳轉(zhuǎn)到賺金幣頁面
    • 金幣兌換道具:跳轉(zhuǎn)到兌換道具頁
  2. 未登錄狀態(tài):
    • 登錄:判斷用戶輸入的賬號密碼,正確提示用戶登錄成功。
    • 退出登錄:提示用戶已經(jīng)退出過了。
    • 查看賬戶金幣:提示用戶請先登錄
    • 賺取金幣:跳轉(zhuǎn)到賺金幣頁(這里也可以提示用戶登錄,具體看產(chǎn)品定的登錄時(shí)機(jī))
    • 金幣兌換道具:提示用戶請先登錄

想必看完這個(gè)示例,大家已經(jīng)對狀態(tài)模式有了一些自己的見解。

這種情況下,非常適合使用狀態(tài)模式。

如果項(xiàng)目中,還是通過判斷語句來進(jìn)行狀態(tài)的區(qū)分,就說明這個(gè)項(xiàng)目沒有很好地應(yīng)用狀態(tài)模式。

下面我們就來將上述案例轉(zhuǎn)化成代碼。

首先是狀態(tài)行為的抽象,該抽象包含了所有的行為:

public interface UserState {

    //登錄
    void login();

    //登出
    void logout();

    //查詢余額
    void seeMoney();

    //賺金幣
    void earnMoney();

    //兌換道具
    void exchange();
}

針對我們上面描述的示例,有以上5種行為,我們將其進(jìn)行了抽象。

接著來思考行為的具體實(shí)現(xiàn):登錄狀態(tài)的具體實(shí)現(xiàn)、未登錄狀態(tài)的具體實(shí)現(xiàn)。

具體做起來也很簡單,就是創(chuàng)建兩個(gè)類去實(shí)現(xiàn)我們的行為抽象,在各自的實(shí)現(xiàn)下,去實(shí)現(xiàn)該狀態(tài)下,應(yīng)該做的事情。

首先來看登錄狀態(tài):

public class LoginStateImpl implements UserState {
    @Override
    public void login() {
        Toast.makeText(App.context, "您已經(jīng)登錄了,無需登錄!", Toast.LENGTH_SHORT).show();
    }

    @Override
    public void logout() {

        Toast.makeText(App.context, "退出登錄成功!", Toast.LENGTH_SHORT).show();
    }

    @Override
    public void seeMoney() {
        Toast.makeText(App.context, "您目前有100金幣", Toast.LENGTH_SHORT).show();
    }

    @Override
    public void earnMoney() {
        Toast.makeText(App.context, "跳轉(zhuǎn)到-賺金幣", Toast.LENGTH_SHORT).show();
    }

    @Override
    public void exchange() {
        Toast.makeText(App.context, "跳轉(zhuǎn)到-兌換道具", Toast.LENGTH_SHORT).show();
    }
}

根據(jù)示例需求,我實(shí)現(xiàn)了登錄狀態(tài)下,這5種行為的具體實(shí)現(xiàn)。

未登錄狀態(tài)也是同理,這里就不列舉代碼了,可以直接查看GitHub

接下來我們來看一下測試代碼:

//默認(rèn)是未登錄狀態(tài)
private UserState userState = new LogutStateImpl();

@Override
public void onClick(View view) {
    switch (view.getId()) {
        case R.id.bt_login://登錄行為
            userState.login();
            //核心:更換用戶狀態(tài)
            userState = new LoginStateImpl();
            break;
        case R.id.bt_logout://退出登錄行為
            userState.logout();
            userState = new LogutStateImpl();
            break;
        case R.id.bt_see_money://查看余額行為
            userState.seeMoney();
            break;
        case R.id.bt_earn_money://賺取金幣行為
            userState.earnMoney();
            break;
        case R.id.bt_exchange://兌換行為
            userState.exchange();
            break;
    }
}

這里也是利用多態(tài)的特性,根據(jù)狀態(tài)的變化,注入不同的實(shí)現(xiàn)。

至此,我們已經(jīng)使用狀態(tài)模式成功實(shí)現(xiàn)了上述需求,并且去除了重復(fù)、雜亂的判斷語句,體現(xiàn)出了狀態(tài)模式的精髓。

總結(jié)

代碼已經(jīng)上傳至GitHub,可以下載查閱。

其實(shí)看到這里,各位看官想必已經(jīng)了解了狀態(tài)模式。

狀態(tài)模式的關(guān)鍵點(diǎn)在于:不同狀態(tài)下、同一行為的不同響應(yīng)。

狀態(tài)模式是為了優(yōu)化代碼結(jié)構(gòu)而產(chǎn)生的。我們通過if-else其實(shí)可以完美判斷用戶的登錄狀態(tài),但是這種實(shí)現(xiàn)使得邏輯與具體行為耦合在一起,后期難以維護(hù)。

狀態(tài)模式就是為了消除這種丑態(tài),實(shí)現(xiàn)邏輯與行為的解耦。

當(dāng)然并不是所有的if-else都適合使用狀態(tài)模式,具體是否使用,還是由你來決定。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容