意圖
當一個對象的內在狀態改變時允許改變其行爲,這個對象看起來像是改變了其類。
動機
主要解決的是當控制一個對象狀態轉換的條件表達式過於複雜時的情況。把狀態的判斷邏輯轉移到表示不同的一系列類當中,可以把複雜的邏輯判斷簡單化。
適用性
1) 一個對象的行爲取決於它的狀態, 並且它必須在運行時刻根據狀態改變它的行爲。
2) 代碼中包含大量與對象狀態有關的條件語句:一個操作中含有龐大的多分支的條件(if else(或switch case)語句,且這些分支依賴於該對象的狀態。這個狀態通常用一個或多個枚舉常量表示。通常 , 有多個操作包含這一相同的條件結構。 State模式將每一個條件分支放入一個獨立的類中。這使得你可以根據對象自身的情況將對象的狀態作爲一個對象,這一對象可以不依賴於其他對象而獨立變化。
結構圖
角色
環境類(Context): 定義客戶感興趣的接口。維護一個ConcreteState子類的實例,這個實例定義當前狀態。
抽象狀態類(State): 定義一個接口以封裝與Context的一個特定狀態相關的行爲。
具體狀態類(ConcreteState): 每一子類實現一個與Context的一個狀態相關的行爲。
實現
/// <summary>
/// 電燈類,對應模式中的Context類
/// </summary>
public class Light
{
private LightState state;
public Light(LightState state)
{
this.state = state;
}
/// <summary>
/// 按下電燈開關
/// </summary>
public void PressSwich()
{
state.PressSwich(this);
}
public LightState State
{
get { return state; }
set { state = value; }
}
}
/// <summary>
/// 抽象的電燈狀態類,相當於State類
/// </summary>
public abstract class LightState
{
public abstract void PressSwich(Light light);
}
/// <summary>
/// 具體狀態類, 開
/// </summary>
public class On : LightState
{
/// <summary>
/// 在開狀態下,按下開關則切換到關的狀態。
/// </summary>
/// <param name="light"></param>
public override void PressSwich(Light light)
{
Console.WriteLine("Turn off the light.");
light.State = new Off();
}
}
/// <summary>
/// 具體狀態類,關
/// </summary>
public class Off: LightState
{
/// <summary>
/// 在關狀態下,按下開關則打開電燈。
/// </summary>
/// <param name="light"></param>
public override void PressSwich(Light light)
{
Console.WriteLine("Turn on the light.");
light.State = new On();
}
}
客戶端代碼
class Program
{
static void Main(string[] args)
{
// 初始化電燈,原始狀態爲關
Light light = new Light(new Off());
// 第一次按下開關,打開電燈
light.PressSwich();
// 第二次按下開關,關閉電燈
light.PressSwich();
Console.Read();
}
}
執行結果
Turn on the light
Turn off the light
優缺點
優點
狀態模式將與特定狀態相關的行爲局部化,並且將不同狀態的行爲分割開來。
所有狀態相關的代碼都存在於某個ConcereteState中,所以通過定義新的子類很容易地增加新的狀態和轉換。
狀態模式通過把各種狀態轉移邏輯分不到State的子類之間,來減少相互間的依賴。
State對象可被共享 如果State對象沒有實例變量—即它們表示的狀態完全以它們的類型來編碼—那麼各Context對象可以共享一個State對象。當狀態以這種方式被共享時, 它們必然是沒有內部狀態, 只有行爲的輕量級對象。
缺點
導致較多的ConcreteState子類
狀態模式的結構與實現都較爲複雜,如果使用不當將導致程序結構和代碼的混亂。