12

bbv.Common.StateMachineクラスは私が今まで見た中で最高のステートマシンコードです。しかし、それはただ1つのことを欠いています:現在の状態を取得することです。

これは注文追跡システムです:

fsm = new ActiveStateMachine<States, Events>();

        fsm.In(States.OrderCreated)
            .On(Events.Submitted)
            .Goto(States.WaitingForApproval);
        fsm.In(States.WaitingForApproval)
            .On(Events.Reject)
            .Goto(States.Rejected);
        fsm.In(States.WaitingForApproval)
            .On(Events.Approve)
            .Goto(States.BeingProcessed);
        fsm.In(States.BeingProcessed)
            .On(Events.ProcessFinished)
            .Goto(States.SentByMail);
        fsm.In(States.SentByMail)
            .On(Events.Deliver)
            .Goto(States.Delivered);

        fsm.Initialize(States.OrderCreated);
        fsm.Start();
        fsm.Fire(Events.Submitted);
        // Save this state to database

あなたはそれがどのように簡単に機能するかを見ることができます。

しかし、注文状態をデータベースに保存したいと思います。だから私はどの状態で注文であるかを示すことができます。

私は〜が必要です

fsm.GetCurrentState()
//show this state in the a table

方法。ExecuteOnEntry実際には方法があります。すべての州のエントリでローカル値を使用および変更できます。ExecuteOnEntryしかし、私は自分自身を繰り返すので、すべての州について書くのは面倒です!

それを行うには繊細な方法が必要です。

4

2 に答える 2

17

ダニエルが説明したように、これは仕様によるものです。理由を説明しましょう:

ステートマシンでは、イベントのキューイングが可能です。したがって、ステートマシンに現在の状態について尋ねることは、誤解を招く可能性があります。現在は状態Aですが、状態Bになるイベントがすでにキューに入れられています。

さらに、ステートマシンの内部状態(ステートマシンの定義で使用する状態)をステートマシンの外部状態(データベースに保持する状態)と直接結合することは、悪い設計だと思います。これら2つを直接結合すると、外部(この場合はデータベース)に影響を与えることなく、ステートマシンを内部でリファクタリングする機能が失われます。状態AをA1とA2に分割する必要があるというシナリオに頻繁に遭遇します。これは、それらに異なるアクションをアタッチする必要があるためですが、それでも、それらは環境に対して同じ状態を表しています。したがって、ExecuteOnEntry()で記述したように、またはマッピングを提供して拡張機能を使用することにより、内部状態と外部状態を分離することを強くお勧めします。これは、現在の状態を取得する拡張機能です。

public class CurrentStateExtension : ExtensionBase<State, Event>
{
    public State CurrentState { get; private set; }

    public override void SwitchedState(
        IStateMachineInformation<State, Event> stateMachine, 
        IState<State, Event> oldState, 
        IState<State, Event> newState)
    {
        this.CurrentState = newState.Id;
    }
}

次の方法で、拡張機能をステートマシンに追加できます。

currentStateExtension = new CurrentStateExtension();
machine.AddExtension(currentStateExtension);

もちろん、この拡張機能を直接使用して、現在の状態にアクセスすることもできます。さらに簡単にするために、ステートマシンを定義するクラスに拡張機能を実装させ、それ自体を拡張機能として渡します。余分なクラスを取り除きましょう。

最後の注意:https://groups.google.com/forum/?fromgroups#!forum / appccelerateのGoogleグループでbbv.Common(または現在のAppccelerate)について質問すると、私にとっては簡単です。質問を見つけて答える;-)

于 2012-11-13T12:45:32.540 に答える
6

これは仕様によるものです。ステートマシンの状態を設計臭としてクエリすることを検討します。しかしもちろん例外的なケースもあります。次の2つのオプションがあります。

  1. メソッドを使用してExecuteOnEntry、注文の状態を保存します。これは、ステートマシンの状態をビジネスロジックにリークしたくないため、進むべき道を反映しています。
  2. 内部で使用する独自のステートマシンデコレータを作成しますStateMachine<TState, TEvent>。これにより、状態が公開されます。

ダニエル

于 2012-11-12T20:58:25.193 に答える