狀態(tài)模式

我們開發(fā)項(xiàng)目的過程中通常會碰到一種需求,某個(gè)對象包含多種狀態(tài)變化的可能性,隨著狀態(tài)的變化行為也執(zhí)行不同的動作。


以電梯來舉例:
電梯最基本具備 開門、關(guān)門、上下走動、停止 這四種狀態(tài)。狀態(tài)與狀態(tài)之間有約束的關(guān)系,比如只能在關(guān)門的情況下才能走動。
所以用傳統(tǒng)面向過程的解決方案,就必須要用狀態(tài)值來標(biāo)記每一種狀態(tài),然后用多個(gè)if else語句來判斷狀態(tài)的執(zhí)行順序,每當(dāng)增加一個(gè)新狀態(tài)的時(shí)候就需要重新修改代碼,這樣就不符合開閉原則。

我們來看下如何用狀態(tài)模式來優(yōu)雅的處理問題。

public abstract class LiftState
{
    protected Context context;
    public void setContext(Context context)
    {
        this.context = context;
    }
    public abstract void open();  //電梯開門
    public abstract void close(); //電梯關(guān)門
    public abstract void stop();  //電梯停止
    public abstract void run();   //電梯上下走動
}
//電梯處于開門狀態(tài)
public class OpenState extends LiftState
{
    @Override
    public void open() {
        //本身就處于開門狀態(tài)
        //do nothing
    }
    @Override
    public void close() {
        super.context.setLiftStatus(Context.closeState);  //切換至關(guān)門狀態(tài)
        super.context.getLiftStatus().close(); //委托關(guān)門狀態(tài)類 來執(zhí)行具體的關(guān)門動作
    }
    @Override
    public void stop() {
        //電梯開門狀態(tài)時(shí),本身就停止的
        //do nothing
    }
    @Override
    public void run() {
        //電梯開門狀態(tài)時(shí),不能走動
        //do nothing
    }
}
//電梯走動狀態(tài)
public class RunState extends LiftState
{
    @Override
    public void open() {
        //走動狀態(tài)不能開門
        //do nothing
    }
    @Override
    public void close() {
        //走動狀態(tài)本身就是處于關(guān)門狀態(tài)
        //do nothing
    }
    @Override
    public void stop() {
        super.context.setLiftStatus(Context.stopState);  //切換至停止?fàn)顟B(tài)
        super.context.getLiftStatus().stop(); //委托停止?fàn)顟B(tài)類 來執(zhí)行具體的停止動作
    }
    @Override
    public void run() {
        //本身就處于走動狀態(tài)
        //do nothing
    }
}
//電梯關(guān)門狀態(tài)類
public class CloseState extends LiftState
{
    @Override
    public void open() {
        super.context.setLiftStatus(Context.openStatus);  //切換至開門狀態(tài)
        super.context.getLiftStatus().open(); //委托開門狀態(tài)類 來執(zhí)行具體的開門動作
    }
    @Override
    public void close() {
    }
    @Override
    public void stop() {
    }
    @Override
    public void run() {
        super.context.setLiftStatus(Context.runState);  //切換至走動狀態(tài)
        super.context.getLiftStatus().run(); //委托走動狀態(tài)類 來執(zhí)行具體的走動動作
    }
}
//電梯停止?fàn)顟B(tài)類
public class StopState extends LiftState
{
    @Override
    public void open() {
        super.context.setLiftStatus(Context.openStatus);  //切換至開門狀態(tài)
        super.context.getLiftStatus().open(); //委托開門狀態(tài)類 來執(zhí)行具體的走動動作
    }
    @Override
    public void close() {
    }
    @Override
    public void stop() {
    }
    @Override
    public void run() {
        super.context.setLiftStatus(Context.runState);  //切換至走動狀態(tài)
        super.context.getLiftStatus().run(); //委托走動狀態(tài)類 來執(zhí)行具體的走動動作
    }
}
public class Context
{
    public final static OpenState openStatus = new OpenState();
    public final static CloseState closeState = new CloseState();
    public final static RunState runState = new RunState();
    public final static StopState stopState = new StopState();
    private LiftState curStatus; //當(dāng)前電梯狀態(tài)
    //設(shè)置電梯狀態(tài),并且把當(dāng)前上下文的引用傳遞給具體的狀態(tài)類,具體的狀態(tài)類通過上下文的引用切換不同的狀態(tài)。
    public void setLiftStatus(LiftState liftStatus)
    {
        curStatus = liftStatus;
        liftStatus.setContext(this);
    }
    //獲取當(dāng)前的電梯狀態(tài)
    public LiftState getLiftStatus()
    {
        return curStatus;
    }
    public void open()
    {
        curStatus.open();
    }
    public void close()
    {
        curStatus.close();
    }
    public void stop()
    {
        curStatus.stop();
    }
    public void run()
    {
        curStatus.run();
    }
}
//客戶端類
public class Client
{
    public static void main()
    {
        Context context = new Context();
        context.setLiftStatus(new CloseState());  //電梯初始化為關(guān)門狀態(tài)
        context.open();
        context.close();
        context.run();
        context.stop();
    }
}

需要說明的一點(diǎn)是:
Context 是一個(gè)上下文角色,它的作用就是串聯(lián)各個(gè)狀態(tài)的過渡,在LifeState抽象類中我們定義了并把這個(gè)上下文組合進(jìn)來,病傳遞到了子類。也就是四個(gè)具體狀態(tài)類根據(jù)上下文的環(huán)境來決定如何進(jìn)行狀態(tài)的過渡。

狀態(tài)模式的優(yōu)點(diǎn):
首先,每個(gè)狀態(tài)類都很簡潔,同時(shí)也不需要用 if else 來判斷狀態(tài)的切換。
同時(shí),如果我們要新增狀態(tài)只需要創(chuàng)建新的狀態(tài)類即可,是通過擴(kuò)展而非修改的方式來實(shí)現(xiàn)功能,這是面向?qū)ο蟮囊粋€(gè)重要原則,開閉原則。非常完美。

最后編輯于
?著作權(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)容

  • 1 場景問題# 1.1 實(shí)現(xiàn)在線投票## 考慮一個(gè)在線投票的應(yīng)用,要實(shí)現(xiàn)控制同一個(gè)用戶只能投一票,如果一個(gè)用戶反復(fù)...
    七寸知架構(gòu)閱讀 2,043評論 7 53
  • 3.4 模擬工作流## 做企業(yè)應(yīng)用的朋友,大多數(shù)都接觸過工作流,至少處理過業(yè)務(wù)流程。當(dāng)然對于工作流,復(fù)雜的應(yīng)用可能...
    七寸知架構(gòu)閱讀 2,270評論 1 53
  • 模式定義 允許一個(gè)對象在其內(nèi)部狀態(tài)發(fā)生改變時(shí)改變它的行為。對象看起來似乎修改了它的類。 狀態(tài)模式(State Pa...
    FX_SKY閱讀 357評論 0 0
  • 設(shè)計(jì)模式文章陸續(xù)更新 java單例模式j(luò)ava代理模式j(luò)ava工廠模式 狀態(tài)模式(State)-老孫七十二變 俺老...
    林銳波閱讀 1,387評論 3 9
  • 樹影在陽光中搖曳 庭院里,母親在梧桐下打盹 滑落的書本灑落一地舊相片 自言自語的夢囈 重復(fù)著關(guān)于我的童年 混入秋風(fēng)...
    鄭凌霄閱讀 272評論 1 10

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