狀態(tài)模式

1、定義、使用場(chǎng)景

定義:在不同的狀態(tài)下,對(duì)同一行為有不同的響應(yīng)。狀態(tài)模式把對(duì)象的行為包裝在不同的狀態(tài)中,每一個(gè)狀態(tài)的對(duì)象都有一個(gè)相同的抽象狀態(tài)基類,并實(shí)現(xiàn)基類對(duì)應(yīng)的方法。這樣當(dāng)一個(gè)對(duì)象的狀態(tài)發(fā)生改變時(shí),其行為也會(huì)隨之改變。

使用場(chǎng)景:當(dāng)一個(gè)對(duì)象的行為受其對(duì)應(yīng)的狀態(tài)的影響時(shí)。例如:手機(jī)的飛行模式打開和關(guān)閉是兩個(gè)狀態(tài),在關(guān)閉飛行模式時(shí)可以打電話、發(fā)短信,打開飛行模式時(shí),雖然打電話和發(fā)短信的功能存在,但卻無法正常使用。

2、角色

State:抽象狀態(tài)類或者接口,其中的方法表示對(duì)應(yīng)狀態(tài)下的行為。
StateA、StateBState的具體實(shí)現(xiàn)類,以實(shí)現(xiàn)對(duì)應(yīng)狀態(tài)下具體的行為。
Context:維護(hù)當(dāng)前對(duì)象所對(duì)應(yīng)的狀態(tài)。

3、實(shí)現(xiàn)

App中登錄操作是常見的功能,例如在使用京東、或者淘寶購物時(shí),在用戶未登錄的狀態(tài)下只能進(jìn)行商品的瀏覽,如果點(diǎn)擊購買按鈕,則會(huì)跳轉(zhuǎn)到登錄界面,用戶登陸后則可進(jìn)行商品購買操作。可見在登錄與否的狀態(tài)下,對(duì)于購買的操作有著不同的響應(yīng)處理。接下來我們來模擬這個(gè)簡單的過程。

首先我們定義一個(gè)State接口,里邊包含一個(gè)購買的方法。

public interface UserState {
    void buy(Context context);
}

然后在登錄狀態(tài)與未登錄狀態(tài)下分別實(shí)現(xiàn)這個(gè)接口:

public class LoginState implements UserState {
    @Override
    public void buy(Context context) {
        Toast.makeText(context, "購買成功!", Toast.LENGTH_SHORT).show();
    }
}
public class LogoutState implements UserState {
    @Override
    public void buy(Context context) {
        context.startActivity(new Intent(context, LoginActivity.class));
    }
}

在登錄狀態(tài)下,則直接進(jìn)行購買操作,通過Toast提示購買成功。在未登錄狀態(tài)下則跳轉(zhuǎn)到登錄界面。

接下來定義一個(gè)LoginContext類,來維護(hù)用戶當(dāng)前的登錄狀態(tài):

public class LoginContext {
    //默認(rèn)未登錄
    private UserState currentState = new LogoutState();

    private LoginContext() {
    }

    //通過單例模式獲得LoginContext的對(duì)象
    public static LoginContext getInstance() {
        return SingletonHolder.instance;
    }

    private static class SingletonHolder {
        private static final LoginContext instance = new LoginContext();
    }

    //設(shè)置登錄狀態(tài)
    public void setState(UserState state) {
        currentState = state;
    }

    //購買操作
    public void buy(Context context) {
        currentState.buy(context);
    }
}

可以看到,通過setState()方法來更改用戶登錄狀態(tài),在不同的狀態(tài)下 currentState.buy(context)操作有著不同的響應(yīng):購買成功或者登錄跳轉(zhuǎn)。即不同的狀態(tài)對(duì)象可對(duì)同一個(gè)操作進(jìn)行不同的處理。

我們創(chuàng)建一個(gè)MainActiciy,里邊包含購買和退出登錄兩個(gè)操作:

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        findViewById(R.id.buy).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                LoginContext.getInstance().buy(MainActivity.this);
            }
        });

        findViewById(R.id.logout).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                LoginContext.getInstance().setState(new LogoutState());
                Toast.makeText(MainActivity.this, "已退出登錄", Toast.LENGTH_SHORT).show();
            }
        });
    }
}

同時(shí)還需要一個(gè)LoginActivity進(jìn)行登錄操作:

public class LoginActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_login);

        findViewById(R.id.login).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                LoginContext.getInstance().setState(new LoginState());
                Toast.makeText(LoginActivity.this, "登錄成功", Toast.LENGTH_SHORT).show();
                finish();
            }
        });
    }
}

運(yùn)行后如下:


MainActivity

由于LoginContext中的默認(rèn)狀態(tài)為未登錄,則點(diǎn)擊購買按鈕會(huì)跳轉(zhuǎn)到登錄界面:


LoginActivity

點(diǎn)擊登錄按鈕后,則在LoginContext中會(huì)將當(dāng)前用戶狀態(tài)修改為已登錄,同時(shí)返回主頁,此時(shí)點(diǎn)擊購買按鈕則會(huì)提示購買成功:


Buy.PNG

再點(diǎn)擊退出登錄,則在LoginContext中又會(huì)將當(dāng)前用戶狀態(tài)修改為未登錄。之后再購買的話有需要先進(jìn)行登錄操作。

4、小結(jié)

如果不采用狀態(tài)模式,則在所有購買操作的地方都要先進(jìn)行登錄檢測(cè),這樣可能會(huì)出現(xiàn)大量的if-else邏輯,如果繼續(xù)增加用戶的狀態(tài),則邏輯判斷會(huì)更加的復(fù)雜,增加代碼的維護(hù)難度,一不小心可能會(huì)出現(xiàn)權(quán)限的問題。通過狀態(tài)模式,我們將具體的行為封裝到狀態(tài)類中,省去了if-else判斷,如果要增加狀態(tài)則只需要添加新的State實(shí)現(xiàn)類即可,不用去修改具體的業(yè)務(wù)邏輯,更加的靈活、方便擴(kuò)展。

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

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

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