Design Pattern : State
作者: JB
State pattern使用的時機及範例,可以網路上很多文章。
主要是使用在有順序的事件上,可以免除if…else…或swith…case…的程式碼。
當然缺點就是要多一層去做State管理,以及多出多支對應的State class。
這邊會以實務上:依序做四次電文的傳送為範例。
每一次的電文傳送就是一種狀態(State)
1.
先定義四種電文的類型(State種類)
/// <summary>
/// 狀態種類
/// </summary>
public enum
StateKind
{
/// <summary>
/// 流程一
/// </summary>
A1,
/// <summary>
/// 流程二
/// </summary>
A2,
/// <summary>
/// 流程三
/// </summary>
T1,
/// <summary>
/// 流程四
/// </summary>
T2
}
2.
定義State Pattern的核心類別:State 以及 Context
State : abstract class, 負責設定Context內容,以及設定某種狀態下需要執行的工作。
Context:負責存放目前執行的狀態:State,以及狀態種類:StateKind。
也負責設定哪個State為第一個要執行,和啟動目前狀態下需要執行的工作。
/// <summary>
///
State
/// </summary>
public abstract
class State
{
/// <summary>
/// 執行目前的狀態要做的事情(DoAction),並將目前狀態設定給下一個狀態
/// </summary>
/// <param
name="context">Context類別</param>
/// <returns>訊息</returns>
public abstract String
GetState(Context context);
/// <summary>
/// 執行目前的狀態要做的事情
/// </summary>
public abstract void
DoAction(Context _context);
}
/// <summary>
/// Context
/// </summary>
public class
Context
{
//目前的狀態類別
private
StateKind _stateKind;
//存放狀態
private
State _state;
/// <summary>
/// 建構
/// </summary>
public
Context()
{
this._state = new
A1_State();
//第一個要執行的State
}
/// <summary>
/// 目前的狀態類別
/// </summary>
public StateKind StateKind
{
get
{ return this._stateKind;
}
set
{ this._stateKind = value;
}
}
/// <summary>
/// 存放狀態
/// </summary>
public State State
{
get
{ return this._state;
}
set
{ this._state = value;
}
}
/// <summary>
/// 執行State.GetState ...
/// </summary>
/// <returns>訊息</returns>
public String
GetState()
{
return _state.GetState(this);
}
}
3.
看到這邊,我們應該知道了,只要一直把State存放在Context,做完一個State時,告訴Context換下一個State再繼續做就可以了。
所以我們開始來實作四種State的程式碼… (這邊只列出一個)
/// <summary>
/// 狀態 : A1
/// </summary>
public class
A1_State:State
{
/// <summary>
/// 執行目前的狀態要做的事情(DoAction),並將目前狀態設定給下一個狀態
/// </summary>
/// <param
name="context"></param>
/// <returns>訊息</returns>
public override String
GetState(Context _context)
{
if
(_context.StateKind == StateKind.A1)
{
//執行此狀態要做的事
this.DoAction(_context);
//設定下一個狀態為Auth2
_context.State = new A2_State();
_context.StateKind = StateKind.A2;
}
else
//非此State對應的StateKind
{
//...
}
return
"A1流程結束...";
}
/// <summary>
/// 執行工作
/// </summary>
/// <param
name="_context">Context物件</param>
public override void
DoAction(Context _context)
{
//Step3. 傳送電文
Console.WriteLine("開始傳送A1電文");
}
}
4.
各自完成了A1、A2、T1、T2的覆寫State程式碼後,
接下來只要在主程式,宣告一個Context物件來啟動紀錄在其中的State動作即可。
請注意主程式並不用知道傳送電文的順序, 主程式只要知道總共有幾個電文要送就行了。
Context _context = new Context();
String step1Msg = _context.GetState();
Console.WriteLine(step1Msg);
String step2Msg = _context.GetState();
Console.WriteLine(step2Msg);
String step3Msg = _context.GetState();
Console.WriteLine(step3Msg);
String step4Msg = _context.GetState();
Console.WriteLine(step4Msg);
執行結果 …………
開始傳送A1電文
A1流程結束...
開始傳送A2電文
A2流程結束...
開始傳送T1電文
T1流程結束...
開始傳送T2電文
T2流程結束...