溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

如何理解Java設(shè)計模式的狀態(tài)模式

發(fā)布時間:2021-11-08 09:04:00 來源:億速云 閱讀:110 作者:iii 欄目:開發(fā)技術(shù)

本篇內(nèi)容介紹了“如何理解Java設(shè)計模式的狀態(tài)模式”的有關(guān)知識,在實(shí)際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!

一、什么是狀態(tài)模式

定義:當(dāng)一個對象的內(nèi)在狀態(tài)改變時允許改變其行為,這個對象看起來像是改變了其類。

主要解決:當(dāng)控制一個對象狀態(tài)的條件表達(dá)式過于復(fù)雜時的情況。把狀態(tài)的判斷邏輯轉(zhuǎn)移到表示不同狀態(tài)的一系列類中,可以把復(fù)雜的判斷邏輯簡化。

意圖:允許一個對象在其內(nèi)部狀態(tài)改變時改變它的行為

二、狀態(tài)模式的結(jié)構(gòu)

如何理解Java設(shè)計模式的狀態(tài)模式

在該類圖中,我們看到三個角色:

(1)Context: 環(huán)境類,定義客戶感興趣的接口,維護(hù)一個State子類的實(shí)例,這個實(shí)例對應(yīng)的是對象當(dāng)前的狀態(tài)。

(2)State:抽象狀態(tài)類或者狀態(tài)接口,定義一個或者一組行為接口,表示該狀態(tài)下的行為動作。

(3)ConcreteState: 具體狀態(tài)類,實(shí)現(xiàn)State抽象類中定義的接口方法,從而達(dá)到不同狀態(tài)下的不同行為。

三、狀態(tài)模式的使用場景

1.一個對象的行為取決于它的狀態(tài),并且它必須在運(yùn)行時刻根據(jù)狀態(tài)改變它的行為。

2.一個操作中含有龐大的多分支結(jié)構(gòu),并且這些分支決定于對象的狀態(tài)。

例子:我們在微博上看到一篇文章,覺得還不錯,于是想評論或者轉(zhuǎn)發(fā),但如果用戶沒有登錄,這個時候就會先自動跳轉(zhuǎn)到登錄注冊界面,如果已經(jīng)登錄,當(dāng)然就可以直接評論或者轉(zhuǎn)發(fā)了。這里我們可以看到,我們用戶的行為是由當(dāng)前是否登錄這個狀態(tài)來決定的,這就是典型的狀態(tài)模式情景。

當(dāng)然還包括很多其他動作,例如轉(zhuǎn)發(fā)、分享、打賞等等,都要重復(fù)判斷狀態(tài)才行,如果程序隨著需求的改動或者功能邏輯的增加需要修改代碼,那么你只要遺漏了一個判斷,就會出問題。

而使用狀態(tài)模式,可以很好地避免過多的if–else –分支,狀態(tài)模式將每一個狀態(tài)分支放入一個獨(dú)立的類中,每一個狀態(tài)對象都可以獨(dú)立存在,程序根據(jù)不同的狀態(tài)使用不同的狀態(tài)對象來實(shí)現(xiàn)功能。

四、狀態(tài)模式和策略模式對比

如果我們在編寫代碼的時候,遇到大量的條件判斷的時候,可能會采用策略模式來優(yōu)化結(jié)構(gòu),因?yàn)檫@時涉及到策略的選擇,但有時候仔細(xì)查看下,就會發(fā)現(xiàn),這些所謂的策略其實(shí)是對象的不同狀態(tài),更加明顯的是,對象的某種狀態(tài)也成為判斷的條件。

策略模式的Context含有一個Strategy的引用,將自身的功能委托給Strategy來完成。

我們把Strategy接口改個名字為State,這就是狀態(tài)模式了,同樣Context也有一個State類型的引用,也將自己的部門功能委托給State來完成。

要使用狀態(tài)模式,我們必須明確兩個東西:狀態(tài)和每個狀態(tài)下執(zhí)行的動作。

在狀態(tài)模式中,因?yàn)樗械臓顟B(tài)都要執(zhí)行相應(yīng)的動作,所以我們可以考慮將狀態(tài)抽象出來。

狀態(tài)的抽象一般有兩種形式:接口和抽象類。如果所有的狀態(tài)都有共同的數(shù)據(jù)域,可以使用抽象類,但如果只是單純的執(zhí)行動作,就可以使用接口。

他們之間真正的區(qū)別在策略模式對Strategy的具體實(shí)現(xiàn)類有絕對的控制權(quán),即Context要感知Strategy具體類型。而狀態(tài)模式,Context不感知State的具體實(shí)現(xiàn),Context只需調(diào)用自己的方法,這個調(diào)用的方法會委托給State來完成,State會在相應(yīng)的方法調(diào)用時,自動為Context設(shè)置狀態(tài),而這個過程對Context來說是透明的,不被感知的。

五、狀態(tài)模式的優(yōu)缺點(diǎn)

優(yōu)點(diǎn):

1、封裝了轉(zhuǎn)換規(guī)則。

2、枚舉可能的狀態(tài),在枚舉狀態(tài)之前需要確定狀態(tài)種類。

3、將所有與某個狀態(tài)有關(guān)的行為放到一個類中,并且可以方便地增加新的狀態(tài),只需要改變對象狀態(tài)即可改變對象的行為。

4、允許狀態(tài)轉(zhuǎn)換邏輯與狀態(tài)對象合成一體,而不是某一個巨大的條件語句塊。

5、可以讓多個環(huán)境對象共享一個狀態(tài)對象,從而減少系統(tǒng)中對象的個數(shù)。

缺點(diǎn):

1、狀態(tài)模式的使用必然會增加系統(tǒng)類和對象的個數(shù)。

2、狀態(tài)模式的結(jié)構(gòu)與實(shí)現(xiàn)都較為復(fù)雜,如果使用不當(dāng)將導(dǎo)致程序結(jié)構(gòu)和代碼的混亂。

3、狀態(tài)模式對“開閉原則”的支持并不太好,對于可以切換狀態(tài)的狀態(tài)模式,增加新的狀態(tài)類需要修改那些負(fù)責(zé)狀態(tài)轉(zhuǎn)換的源代碼,否則無法切換到新增狀態(tài);而且修改某個狀態(tài)類的行為也需修改對應(yīng)類的源代碼。

六、狀態(tài)模式的實(shí)現(xiàn)

抽象狀態(tài)類,定義一個接口以封裝與Context類(Work)的一個特定狀態(tài)相關(guān)的行為。

public abstract class State
{
    public abstract void WriteProgram(Work w);
}

工作狀態(tài)類,每一個子類實(shí)現(xiàn)一個與Context類(Work)的一個狀態(tài)相關(guān)的行為。

//上午工作狀態(tài)
public class ForeNoonState : State
{
    public override void WriteProgram(Work w)
    {
        if (w.Hour < 12)
        {
            Console.WriteLine("當(dāng)前時間:{0}點(diǎn),上午工作,精神百倍", w.Hour);
        }
        else
        {
            //超過12點(diǎn),則轉(zhuǎn)入中午工作狀態(tài)
            w.SetState(new NoonState());
            w.WriteProgram();
        }
    }
}
//中午工作狀態(tài)
public class NoonState : State
{
    public override void WriteProgram(Work w)
    {
        if (w.Hour < 13)
        {
            Console.WriteLine("當(dāng)前時間:{0}點(diǎn),吃午飯,午休", w.Hour);
        }
        else
        {
            //超過13點(diǎn),則轉(zhuǎn)入下午工作狀態(tài)
            w.SetState(new AfterNoonState());
            w.WriteProgram();
        }
    }
}
//下午工作狀態(tài)
public class AfterNoonState : State
{
    public override void WriteProgram(Work w)
    {
        if (w.Hour < 17)
        {
            Console.WriteLine("當(dāng)前時間:{0}點(diǎn),下午工作,繼續(xù)努力", w.Hour);
        }
        else
        {
            //超過17點(diǎn),則轉(zhuǎn)入晚上工作狀態(tài)
            w.SetState(new EveningState());
            w.WriteProgram();
        }
    }
}
//晚上工作狀態(tài)
public class EveningState : State
{
    public override void WriteProgram(Work w)
    {
        if (w.Finish)
        {
            //如果狀態(tài)已完成,則轉(zhuǎn)入下班狀態(tài)
            w.SetState(new RestState());
            w.WriteProgram();
        }
        else
        {
            if (w.Hour < 21)
            {
                Console.WriteLine("當(dāng)前時間:{0}點(diǎn),加班", w.Hour);
            }
            else
            {
                //超過21點(diǎn),則轉(zhuǎn)入睡眠工作狀態(tài)
                w.SetState(new SleepingState());
                w.WriteProgram();
            }
        }
    }
}
//睡眠工作狀態(tài)
public class SleepingState : State
{
    public override void WriteProgram(Work w)
    {
        Console.WriteLine("當(dāng)前時間:{0}點(diǎn),睡覺", w.Hour);
    }
}
//下班休息狀態(tài)
public class RestState : State
{
    public override void WriteProgram(Work w)
    {
        Console.WriteLine("當(dāng)前時間:{0}點(diǎn),下班", w.Hour);
    }
}

工作類,Context類,維護(hù)一個ConcreteState子類(工作狀態(tài)類)的實(shí)例,這個實(shí)例定義當(dāng)前的狀態(tài)

public class Work
{
    private State current;
    public Work()
    {
        //工作初始化為上午工作狀態(tài)
        current = new ForeNoonState();
    }
    //“鐘點(diǎn)”屬性,狀態(tài)轉(zhuǎn)換的依據(jù)
    private double hour;
    public double Hour
    {
        get { return hour; }
        set { hour = value; }
    }
    //“任務(wù)完成”屬性,是否能下班的依據(jù)
    private bool finish = false;
    public bool Finish
    {
        get { return finish; }
        set { finish = value; }
    }
     public void SetState(State s)
    {
        current = s;
    }
     public void WriteProgram()
    {
        current.WriteProgram(this);
    }
}

客戶端代碼

class Program
{
    //客戶端代碼
    static void Main(string[] args)
    {
        Work w = new Work();
        w.Hour = 9;
        w.WriteProgram();
        w.Hour = 10;
        w.WriteProgram();
        w.Hour = 12;
        w.WriteProgram();
        w.Hour = 13;
        w.WriteProgram();
        w.Hour = 14;
        w.WriteProgram();
        w.Hour = 17;
         w.Finish = false;
        //w.Finish = true;
        w.WriteProgram();
        w.Hour = 19;
        w.WriteProgram();
        w.Hour = 22;
        w.WriteProgram();
         Console.Read();
    }
}

結(jié)果

當(dāng)前時間:9點(diǎn),上午工作,精神百倍
當(dāng)前時間:10點(diǎn),上午工作,精神百倍
當(dāng)前時間:12點(diǎn),吃午飯,午休
當(dāng)前時間:13點(diǎn),下午工作,繼續(xù)努力
當(dāng)前時間:14點(diǎn),下午工作,繼續(xù)努力
當(dāng)前時間:17點(diǎn),加班
當(dāng)前時間:19點(diǎn),加班
當(dāng)前時間:22點(diǎn),睡覺

“如何理解Java設(shè)計模式的狀態(tài)模式”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識可以關(guān)注億速云網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實(shí)用文章!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI