Unity【話大】設計模式之狀態模式

weixin_34402408發表於2019-01-31

前言:筆者在最開始寫程式的時候經常會遇到一種情況,例如更改一個欄位、或者新增一種小功能,就要把原來寫過的東西幾乎廢棄掉,或者更改大量以前寫過的程式碼。又或者自己寫的東西時間久了再去回顧,完全找不到到時為什麼這麼寫的頭緒,如果遇到了Bug更是無法快速定位在哪裡小範圍出現的問題。如果你也經常遇到這種問題,就說明你現階段非常需要學習下設計模式了

在網上經常說的設計模式有23種,也有一些更多的設計模式,無非也是從這些設計模式中變種而來。如果讓筆者來形容什麼是設計模式,我認為設計模式是:一種思想,一種模式,一種套路,一種解決問題的高效策略



有說的不正確或者不準確的地方歡迎留言指正


有什麼有趣的寫作技巧或者想法歡迎大家給我留言,大家的幫助是我寫下去最有效的動力



7643202-d7db5b83dc611de7.png

今天筆者跟大家介紹一個新的設計模式----狀態模式,下面以有A、B、C三個狀態進行分別跳轉,跳轉順序A--->B--->C,且這3個狀態會有自己行為方式,就以這個示例展示狀態模式如何使用

狀態模式(State) 當一個物件的內在狀態改變時允許改變其行為,這個物件看起來像是改變了其類。

初始程式碼

public class Context
{
    public string state;

    public void Change()
    {
        if (state =="A")
        {
            this.Log("執行A先關操作");
        }
        else if (state  =="B")
        {
            this.Log("執行B先關操作");
        }
        else if (state == "C")
        {
            this.Log("執行C先關操作");
        }
    }
}

呼叫

    void Start()
    {
        Context context = new Context();
        context.state = "A";
        context.Change();
        context.state = "B";
        context.Change();
        context.state = "C";
        context.Change();
    }
對應列印日誌
7643202-dddbbceaa29c5e6f.png

老套路,我們開始進行抽象 封裝和轉移

首先我們把其中的if else判斷中的行為進行封裝,轉移到不同的state中自行管理

public abstract class State
{
    public abstract void Handle();
}
public class StateA : State
{
    public override void Handle()
    {
        this.Log("執行A先關操作1");
        this.Log("執行A先關操作2");
        this.Log("執行A先關操作3");
    }
}

public class StateB : State
{
    public override void Handle()
    {
        this.Log("執行B先關操作1");
        this.Log("執行B先關操作2");
        this.Log("執行B先關操作3");
    }
}

public class StateC : State
{
    public override void Handle()
    {
        this.Log("執行C先關操作1");
        this.Log("執行C先關操作2");
        this.Log("執行C先關操作3");
    }
}

對應Context中的更改

public class Context
{
    public State state;

    public void SetState(State state)
    {
        this.state = state;
    }

    public void Change()
    {
        if (state is StateA)
        {
            state.Handle();
        }
        else if (state is StateB)
        {
            state.Handle();
        }
        else if (state is StateC)
        {
            state.Handle();
        }
    }
}

呼叫就變成了這個樣子

    void Start()
    {
        Context context = new Context();
        context.state = new StateA();
        context.Change();
        context.state = new StateB();
        context.Change();
        context.state = new StateC();
        context.Change();
    }

因為是他是按順序的跳轉機制,我們再次改造 ,把相關的跳轉封裝到各自的state中去

State

public abstract class State
{
    public abstract void Handle();
    public abstract void Change(Context context);
}
public class StateA : State
{
    public override void Handle()
    {
        this.Log("執行-- A --先關操作1");
    }

    public override void Change(Context context)
    {
        Handle();
        context.state = new StateB();
    }
}

public class StateB : State
{
    public override void Handle()
    {
        this.Log("執行-- B --先關操作1");
    }
    public override void Change(Context context)
    {
        Handle();
        context.state = new StateC();
    }
}

public class StateC : State
{
    public override void Handle()
    {
        this.Log("執行-- C --先關操作1");
    }

    public override void Change(Context context)
    {
        Handle();
        context.state = new StateA();
    }
}

Contenxt

public class Context
{
    public State state;

    public Context(State state)
    {
        this.state = state;
    }

    public void Change()
    {
        state.Change(this);
    }
}

呼叫

    void Start()
    {
        Context context = new Context(new StateA());
        context.Change();        //執行A並跳轉B狀態
        context.Change();        //執行B並跳轉C狀態
        context.Change();        //執行C並跳轉A狀態

        context.Change();        //執行A並跳轉B狀態
        context.Change();        //執行B並跳轉C狀態
        context.Change();        //執行C並跳轉A狀態
    }
7643202-b1a0134eb356c869.png

以上就是狀態模式的最終版。狀態模式主要解決的是當控制一個物件狀態裝換的條件表示式過於複雜時的情況。把狀態的判斷邏輯轉移到表示不同狀態的一系列類當中,可以把複雜的判斷邏輯簡化。

所以當一個物件的行為取決於它的狀態,並且他必須在執行時刻根據狀態改變它的行為時,就可以考慮使用狀態模式。

狀態模式好處與用處

狀態模式的好處是將與特定狀態相關的行為區域性化,並且將不同狀態的行為分割開來
將特定的狀態相關的行為都放入一個物件中,由於所有與狀態相關的程式碼都存在於某個ConcreteState中,所以通過定義新的子類可以很容易地增加新的裝填和轉換。
狀態模式通過把各種狀態轉移邏輯分佈到State的子類之間,來減少相互間的依賴

優點:

1、封裝了轉換規則,也就是將與特定狀態相關的行為區域性化,並且將不同狀態的行為分割開來
2、列舉可能的狀態,在列舉狀態之前需要確定狀態種類。
3、將所有與某個狀態有關的行為放到一個類中,並且可以方便地增加新的狀態只需要改變物件狀態即可改變物件的行為。
4、允許狀態轉換邏輯與狀態物件合成一體,而不是某一個巨大的條件語句塊。
5、可以讓多個環境物件共享一個狀態物件,從而減少系統中物件的個數。

缺點:

1、狀態模式的使用必然會增加系統類和物件的個數。
2、狀態模式的結構與實現都較為複雜,如果使用不當將導致程式結構和程式碼的混亂。
3、狀態模式對"開閉原則"的支援並不太好,對於可以切換狀態的狀態模式,增加新的狀態類需要修改那些負責狀態轉換的原始碼,否則無法切換到新增狀態,而且修改某個狀態類的行為也需修改對應類的原始碼。

相關文章