曾經的項目中有個小需求,在一個list中創建一個Choice類型的字段,名為 Status,分別有"Not Started","In Progress","On Schedule","ahead of Schedule","Delayed","Done"等等用來表示進度的字段,要求當這個item的 Status值從"Not Started"變為"In Progress"時,給項目經理發郵件,當從"In Progress"變為"ahead of Schedule"時給整個項目組加上部門經理發郵件。
需求就這麼簡單,當時也沒多想,就用Eventhandler實現了,大致代碼如下 :
代碼
string previousStatus = properties.ListItem["Status"] as String;
string currentStatus = properties.AfterProperties["Status"] as String;
if(previousStatus == "Not Started"&¤tStatus == "In Progress")
{
SendEmail(mgr);
}
if(previousStatus == "In Progress"&¤tStatus == "ahead of Schedule")
{
SendEmail(director);
}
很好,這樣的Eventhandler完成了需求,簡單明了。跑了一段時間,業務需 求發生變化了,當從"In Progress"變成"Done"時也要發郵件給Mgr,於是又修改 了代碼中的if condition,但是需求總是在變化,有時候在Eventhandler中不僅 涉及到了Stauts字段變化的處理還有別的字段變化處理,總之 if condition到 後來變的象面條一樣冗長,讓人看了很不舒服,維護起來也很麻煩了。
在代碼review中,我們認識到了這樣的需求變化在Eventhandler開發中太常 見了,於是打算用State模式來改寫以前的代碼,使得我們的擴展更加方便:
State模式的應用場景:在你的類裡面有個型別碼來表示對象的當前狀態,這 個對象的行為通常依賴這個狀態,而且在運行的時候這個狀態會改變,那麼對象 的行為在運行的時候也要跟著改變。一般我們會使用if/else或者switch來根據 這個型別碼來執行相關操作,現在我們有更好的方式來處理 --State模式。
好像這個場景很符合我們當前的情況,於是我們就開始改寫代碼了。根據 State模式類圖,首先創建State的抽象類
public abstract class State
{
public abstract void Select();
}
其次為每個可能的狀態編寫狀態類,繼承自State類
代碼
class InProgressState:State
{
Public StateContext context;
public override void Select()
{
SendEmail(mgr);
}
}
class AheadOfSchedule:State
{
public override void Select()
{
SendEmail(director);
}
}
還有Context類:
代碼
class StateContext
{
State _currentState;
string _currentValue;
public StateContext(string currentValue)
{
this._currentValue = currentValue;
}
public State CurrentState { get; set; }
public string CurrentValue{ get; set; }
public void Process()
{
switch (CurrentValue)
{
case "In Progress":
{
CurrentState = new InProgressState();
CurrentState.Select ();
return;
}
case "Ahead of Schedule":
{
CurrentState = new AheadOfSchedule();
CurrentState.Select ();
return;
}
default:
{
return;
}
}
}
}
Eventhandler調用代碼:
代碼
public override void ItemUpdating(SPItemEventProperties properties)
{
string currentStatus = properties.AfterProperties["Status"] as String;
StateContext context = new StateContext (currentStatus);
context.Process();
}
當然這裡還沒有做到完全抽象,但較之前的情況已經好了很多。
當以後還遇到在Eventhandler中涉及到狀態改變的復雜邏輯時,先考慮State 模式會很有好處。