2013年7月10日 星期三

設計模式:狀態模式 (State Pattern)

狀態模式 (State Pattern),以下程式碼以 C# 為例

說明:
一物件有多個狀態,在不同狀態下有不同的行為。
一般可能會用多個 if else 來處理這些分支行為。
若使用狀態模式,則是將這些分支行為,提取出來,放到另外的 class 處理。
也就是將 if else 拆開,改寫成一個分支一個 class。

這樣做的優點是,複雜的 if else 分支,維護可能較麻煩。
用狀態模式,修改或新增分支時,則只需要修改相關的幾個分支類別即可。

範例:
遊戲中,玩家的等級不同,有不同的稱呼。
假設等級 0~20 => 新手,20~50 => 老手,50~90 => 高手,90 以上=> 神


希望達成如下的效果
static void Main(string[] args)
{
    Player user = new Player();
    user.level = 1; // 玩家等級
    user.stateWork(); // 玩家狀態處理
    user.level = 20;
    user.stateWork();
    user.level = 62;
    user.stateWork();
    user.level = 93;
    user.stateWork();

    Console.ReadLine();
}
執行結果: 
等級 1 (新手)
等級 20 (老手)
等級 62 (高手)
等級 93 (神)

實現重點在於,將每個 if else 改寫成多個單獨的分支類別。
若符合條件的不是某個分支類別,則繼續將流程丟給下一個分支類別處理。

其餘程式碼
// 玩家類別,有一個等級的屬性
public class Player
{
    public int level = 1; // 等級

    /* 狀態處理,一般用 if else 的寫法
    public void stateWork()
    {
        if (level >= 1 && level < 20)
        {
            Console.WriteLine("等級 {0} ({1})", level, "新手");
        }
        else if (level >= 20 && level < 50)
        {
            Console.WriteLine("等級 {0} ({1})", level, "老手");
        }
        else if (level >= 50 && level < 90)
        {
            Console.WriteLine("等級 {0} ({1})", level, "高手");
        }
        else if (level >= 90)
        {
            Console.WriteLine("等級 {0} ({1})", level, "神");
        }
    }
    */

    // 將狀態處理改為以下寫法 (狀態模式)
    private StateContext state;

    public Player()
    {
        // 初始化狀態處理的物件
        setStateContext(new ConcreteState001());
    }

    // 設定狀態處理的物件
    public void setStateContext(StateContext s)
    {
        state = s;
    }

    // 狀態處理,轉交由 StateContext 物件處理
    public void stateWork()
    {
        state.stateWork(this);
    }
}

// 狀態模式的抽象類別
public abstract class StateContext
{
    public abstract void stateWork(Player user);
}

// 等級 1~20
public class ConcreteState001 : StateContext
{
    public override void stateWork(Player user)
    {
        if (user.level < 20)
        {
            Console.WriteLine("等級 {0} ({1})", user.level, "新手");
        }
        else
        {
            user.setStateContext(new ConcreteState050());
            user.stateWork();
        }
    }
}

// 等級 20~50
public class ConcreteState050 : StateContext
{
    public override void stateWork(Player user)
    {
        if (user.level < 50)
        {
            Console.WriteLine("等級 {0} ({1})", user.level, "老手");
        }
        else
        {
            user.setStateContext(new ConcreteState090());
            user.stateWork();
        }
    }
}

// 等級 50~90
public class ConcreteState090 : StateContext
{
    public override void stateWork(Player user)
    {
        if (user.level < 90)
        {
            Console.WriteLine("等級 {0} ({1})", user.level, "高手");
        }
        else
        {
            user.setStateContext(new ConcreteStateMAX());
            user.stateWork();
        }
    }
}

// 等級 90~
public class ConcreteStateMAX : StateContext
{
    public override void stateWork(Player user)
    {
        if (user.level >= 90)
        {
            Console.WriteLine("等級 {0} ({1})", user.level, "神");
        }
    }
}

相關連結:設計模式整理列表

沒有留言:

張貼留言