1. 程式人生 > >設計模式(二十一)—— 狀態模式

設計模式(二十一)—— 狀態模式

uml public bubuko interface 對象 con 原理 處理 環境

模式簡介


允許一個對象在其內部狀態改變時改變它的行為。對象看起來似乎修改了它的類。

在某些情況下,一個對象的行為取決於它當前所處的狀態,當對象屬性(狀態)在系統運行過程中發生變化,它呈現出的行為也隨之發生改變。例如可調節亮度的臺燈,假設燈光亮度分為三級,每次按下按鈕,臺燈會根據當前亮度增加一級,若已經是最亮的狀態,按下按鈕則關閉臺燈。

結構分析


UML類圖

技術分享圖片

角色說明

  • Context

環境類。客戶端操作的類,包含一個IState類型的對象,保存其當前狀態。

  • IState

狀態接口。定義一個統一的接口以封裝與Context的特定狀態相關的行為。

  • ConcreteState

具體狀態。實現狀態接口,表示Context某個狀態相關的行為。

工作原理

Context類將與狀態相關的請求委托給ConcreteState對象處理,並將自身以參數形式傳遞給ConcreteState對象,如此,便可以在處理完請求後訪問Context的SetState方法為Context設置新的狀態。

結構代碼

//環境類
class Context
{
    private IState _state;
    public Context(IState state)
    {
        _state = state;
        Console.WriteLine($"Initialize state -> {state}");
    }

    public void SetState(IState state)
    {
        _state = state;
        Console.WriteLine($"Set State -> {state}");
    }

    public void Request()
    {
        _state.Handle(this);
    }
}

//狀態接口
interface IState
{
    void Handle(Context context);
}

//具體狀態類A
class ConcreteStateA : IState
{
    public void Handle(Context context)
    {
        context.SetState(new ConcreteStateB());
    }
}

//具體狀態類B
class ConcreteStateB : IState
{
    public void Handle(Context context)
    {
        context.SetState(new ConcreteStateA());
    }
}

//客戶端調用
static void Main(string[] args)
{
    Context context = new Context(new ConcreteStateA());
    for (int i = 0; i < 5; i++)
    {
        context.Request();
    }
    Console.ReadLine();
}

程序輸出:

技術分享圖片

示例分析


本節模擬第一節中提到的臺燈示例。首先創建臺燈類Lamp,提供共有方法SetState設置當前狀態,包含一個保存當前狀態的私有字段_state,並通過Request方法調用該狀態的下臺燈發光的行為。

class Lamp
{
    private IState _state;
    public Lamp(IState state)
    {
        _state = state;
        Console.WriteLine($"Initialize state -> {state}");
    }
    public void SetState(IState state)
    {
        _state = state;
        Console.WriteLine($"Set State -> {state}");
    }

    public void Request()
    {
        _state.Handle(this);
    }
}

聲明狀態接口,並分別實現具體狀態類,這裏包括四種狀態Closed、Dim、Medium、Bright。

interface IState
{
    void Handle(Lamp context);
}

class Closed : IState
{
    public void Handle(Lamp context)
    {
        context.SetState(new Dim());
    }
}

class Dim : IState
{
    public void Handle(Lamp context)
    {
        context.SetState(new Medium());
    }
}

class Medium : IState
{
    public void Handle(Lamp context)
    {
        context.SetState(new Bright());
    }
}

class Bright : IState
{
    public void Handle(Lamp context)
    {
        context.SetState(new Closed());
    }
}

客戶端調用,將臺燈的初始狀態設置為Closed,並連續調用,輸出臺燈狀態。

class Program
{
    static void Main(string[] args)
    {
        Lamp lamp = new Lamp(new Closed());
        for (int i = 0; i < 10; i++)
        {
            lamp.Request();
        }
        Console.ReadLine();
    }
}

程序輸出:

技術分享圖片

適用場景


  • 一個對象的行為取決於它的狀態,並且它必須在運行時刻根據狀態改變它的行為。

  • 一個操作中含有大量的分支的條件語句,且這些分支依賴於該對象的狀態。

設計模式(二十一)—— 狀態模式