2014-02-19 48 views
0

我在執行從下面的StackOverflow後一點幫助狀態模式了個去:狀態模式:解耦的MoveNext()方法

state pattern

好爲止。 我現在可以移動的對象(文件,到下一個狀態,即的確認。)現在

public override void MoveNext(Document currDoc, IProcessor currProcessor) 
    {        
     TransitionTo<ACKNOWLEDGED>(() => new ACKNOWLEDGED(_factory, _context)); 
     currProcessor.LogTheChange(currDoc); 
     currProcessor.DoSomethingElse(currDoc) 
    } 

,在改變狀態的過程中,我想在不同的類執行其他操作。 我懷疑將狀態和IP處理器耦合是一個好主意。

我相信國家應該只關心在兩個謹慎的狀態之間變化(在這種情況下是UNACKNOWLEDGED和ACKNOWLLEDED)。

底層對象的實際更新如何發生?據我所知,我已將doc對象傳遞給moveNext()方法,以便它可以在別處傳遞。如果這不正確,那麼我的狀態對象應該如何與IP處理器以分離的方式進行通信,是否應該引發IP處理器將處理的事件?或者,我是否應該將接口作爲MoveNext()方法中的參數傳遞?我懷疑不是。

+0

您是否選擇使用該帖子和「MoveNext」範例,因爲您的狀態以該帖子中呈現的線性方式移動?我的經驗是,許多狀態機在其狀態轉換中都有分支或循環。 – tcarvin

+0

hiya,是的它以線性方式移動。它不需要更復雜的目前..我有的問題是,這個特定的moveNext()方法目前耦合到a)currDoc b)IProcessor。 –

+0

什麼是IProcessor,它來自哪裏? – tcarvin

回答

0

嗯。我會說這個有趣的問題。如果狀態轉換隻有一種效果(使IP處理器執行一些或某些事情),那麼該方法可能很好。

即使狀態發生變化可能會發生很多事情,但是MoveNext()函數是這種變化的唯一方式,那麼僅僅爲了增加更多的處理器和動作可能並不可怕方法。如果您的某個處理器引發異常,您可能最終不得不擔心會發生什麼情況。但是,如果可以從許多地方(許多函數,如MoveNext(),或者如果狀態可以根據條件自行更改)來啓動狀態更改,那麼您將希望具有監視狀態更改的實體。您可以使用某種發佈和訂閱機制,或者僅僅通過約定,因爲某些對象會在您的狀態實體發出消息時觀看。

如果是我,我可能會鉤住我的狀態對象達到類似的spring.net事件系統(​​)。但是,在.net中可能有其他方法可以在不包含spring的情況下執行此操作。

+0

hiya Robert,感謝您的回覆。我將暫時使用我目前的實現,因爲MoveNext()方法是此chage被激發的唯一點。 –

0

我不認爲使用State模式內部應該永遠知道,狀態機存在一類的調用者。因此,我不是客戶代碼Documemt.MoveNext的粉絲。它暴露了很多實現細節。

這裏是一個替換實現中,隱藏文檔類內的狀態模式。請注意,我用的私有內部類完全隱藏狀態機的細節,而從withing每個狀態子類提供文檔成員的完全訪問權限。我仍然保持這些內部類在自己的代碼文件,但爲了避免在文檔類文件代碼的混亂。

Document.cs

partial class Document 
{ 

    public Document() 
    { 
     // default/starting state 
     this.TransitionToState<EmptyState>(); 
    } 

    // misc data for example 
    public int? caseNumber { get; private set;} 
    public DateTime? WhenSubmitted { get; private set; } 
    public DateTime? WhenAcknowlegded { get; private set; } 
    public int? CompletionStatus { get; private set; } 

    // transitions: EMPTY -> ASSIGNED -> UNACKNOWLEDGED -> ACKNOWLEDGED -> COMPLETED 
    private DocumentState State { get; set; } 


    // state-related methods are forwarded to the current DocumentState instance 

    public void AssignCase(int caseNumber) 
    { 
     State.AssignCase(caseNumber); 
    } 

    public void SubmitTo(object clientInfo) 
    { 
     State.SubmitTo(clientInfo); 
    } 

    public void Acknowledged(object ackInfo) 
    { 
     State.Acknowledged(ackInfo); 
    } 

    public void Complete(int statusCode)   
    { 
     State.Complete(statusCode); 
    } 

    // events could be used for this callback as well, but using private inner 
    // classes calling a private member is probably the simplest. 

    private void TransitionToState<T>() where T : DocumentState, new() 
    { 
     // save prior for a moment 
     DocumentState priorState = State; 

     // this can be lookup from map instead of new() if you need to keep them 
     // alive for some reason. I personally like flyweight states. 
     DocumentState nextState = new T(); 

     // activate the new state. it will get notified so it can do any one- 
     // time setup 
     State = nextState; 
     State.EnterState(this); 

     // let the prior state know as well, so it can cleanup if needed 
     if (priorState != null) 
      priorState.ExitState(); 

    }   

} 

DocumentState。CS

partial class Document 
{ 

    abstract class DocumentState 
    { 

     //-------------------------------------------- 
     // state machine infrastructure 
     //-------------------------------------------- 

     public void EnterState(Document context) 
     { 
      this.Context = context; 
      Console.WriteLine("Entering state: " + this.GetType().Name); // debug only 
      OnEnterState(); 
     } 

     public void ExitState() 
     { 
      this.Context = null; 
      OnExitState(); 
      Console.WriteLine("State that was exited: " + this.GetType().Name); // debug only 
     } 

     protected Document Context { get; private set; } 

     //-------------------------------------------- 
     // a mirror of the document-manipulation methods that concerns states 
     //-------------------------------------------- 

     public void AssignCase(int caseNumber) 
     { 
      OnAssignCase(caseNumber); 
     } 

     public void SubmitTo(object clientInfo) 
     { 
      OnSubmitTo(clientInfo); 
     } 

     public void Acknowledged(object ackInfo) 
     { 
      OnAcknowledged(ackInfo); 
     } 

     public void Complete(int statusCode) 
     { 
      OnComplete(statusCode); 
     } 

     //-------------------------------------------- 
     // state subclasses override the methods they need. Typically not 
     // all are needed by all states. Default implementation is to 
     // throw an exception if a state receives and "unexpected" invocation. 
     //-------------------------------------------- 

     protected virtual void OnAssignCase(int caseNumber) 
     { 
      throw new InvalidOperationException(); 
     } 

     protected virtual void OnSubmitTo(object clientInfo) 
     { 
      throw new InvalidOperationException(); 
     } 

     protected virtual void OnAcknowledged(object ackInfo) 
     { 
      throw new InvalidOperationException(); 
     } 

     protected virtual void OnComplete(int statusCode) 
     { 
      throw new InvalidOperationException(); 
     } 

     //-------------------------------------------- 
     // additional hooks that can be override if needed that signal the 
     // enter and exit of the state. 
     //-------------------------------------------- 

     protected virtual void OnEnterState() 
     { 
     } 

     protected virtual void OnExitState() 
     { 
     } 

    } 

} 

狀態類(我加了用於說明目的額外的):

partial class Document 
{ 

    // Represents an empty document waiting to get assigned a case #. Once 
    // that is satisfied, it performs its logic and triggers a state 
    // transition to the next state. 
    class EmptyState : DocumentState 
    { 
     protected override void OnAssignCase(int caseNumber) 
     { 
      // business logic 
      Context.caseNumber = caseNumber; 
      // write to log 
      // etc, etc 

      // goto next state 
      Context.TransitionToState<AssignedState>(); 
     } 
    } 

} 

partial class Document 
{ 

    // Represents an document assigned a ase number but not submitted to a 
    // client yet. Once that happens it performs its logic and the triggers a state 
    // transition. 
    class AssignedState : DocumentState 
    { 
     protected override void OnSubmitTo(object clientInfo) 
     { 
      // business logic 
      Context.WhenSubmitted = DateTime.Now; 
      // etc 
      // etc 

      // goto next state 
      Context.TransitionToState<UnacknowledgedState>(); 
     } 
    } 
} 

partial class Document 
{   
    // you get the idea by now... 
    class UnacknowledgedState : DocumentState 
    { 
     protected override void OnAcknowledged(object ackInfo) 
     { 
      // business logic 
      Context.WhenAcknowlegded = DateTime.Now; 

      // goto next state 
      Context.TransitionToState<AcknowledgedState>(); 

     } 
    } 
} 

partial class Document 
{ 
    class AcknowledgedState : DocumentState 
    { 
     protected override void OnComplete(int statusCode) 
     { 
      Context.CompletionStatus = statusCode; 

      Context.TransitionToState<CompletedState>(); 
     } 

    } 
} 

partial class Document 
{ 
    class CompletedState : DocumentState 
    { 
     // note there are no methods overriden. this is the last state. 
    } 
} 

最後,Program.cs中:

class Program 
{ 
    static void Main(string[] args) 
    { 
     Console.ReadLine(); 

     Document doc = new Document(); 

     Console.ReadLine(); 

     doc.AssignCase(123456); 

     Console.ReadLine(); 

     doc.SubmitTo("clientAddress"); 

     Console.ReadLine(); 

     doc.Acknowledged("responseFromClient"); 

     Console.ReadLine(); 

     const int TERMS_REJECTED = 123; 
     doc.Complete(TERMS_REJECTED); 

     Console.ReadLine(); 

    } 
} 

讓我知道如果您有任何疑問。