2

タイトル失礼します。

サービス指向アーキテクチャの一部であるシステムがあります。メッセージを受信して​​処理します。このプロセスは、ある場所から別の場所へのデータの移動に簡単に要約できます。システムが下すすべての決定は、システムが常に利用できる 2 つの異なるクラスを検査することによって行うことができます。

  1. 処理中のメッセージ
  2. 特定のデータ操作 (どこからどこへの移動など) の構成情報

ここに主なインターフェースがあります

    public interface IComponent
    {
        bool CanHandle(Message theMessage, Configuration theConfiguration);
        int Priority {get;}
    }

    public interface IComponentLocator<T>
        where T : IComponent
    {
        public LocateComponent(Message theMessage, Configuration theConfiguration);
    }

私は依存関係の逆転の問題に Castle Windsor フレームワークを使用しているため、実装した 1 つのロケーターは、配列リゾルバーを介して注入された適切なコンポーネントをすべて受け取ります。

ここにあります:

public class InjectedComponentsLocator<T> : IComponentLocator<T>
    where T : IComponent
{
    private readonly T[] components;

    public InjectedComponentsLocator(T[] components)
    {
        this.components = components;
        this.components.OrderBy((component) => component.Priority);
    }

    public T LocateComponent(Message theMessage, Configuration theConfiguration)
    {
        List<T> candidates = this.components.Where((h) => h.CanHandle(message, configuration)).ToList();

        if (candidates.Count == 0)
        {
            throw new Exception(string.Format(Resources.UnableToLocateComponentException, typeof(T).Name));
        }
        else if (candidates.Count > 1 && candidates[0].Priority == candidates[1].Priority)
        {
            throw new Exception(string.Format(Resources.AmbiguousComponentException, candidates[0].GetType().Name, candidates[1].GetType().Name));
        }

        return candidates.First();
    }
}

今質問に。インターフェイスのPriorityプロパティIComponent..私はそれが好きではありません。現実には、優先順位は最も具体的なものによって決定できるはずIComponentです。

たとえば、2 つのコンポーネントがあるとします。

    public class HandlesOneRecord : IComponent
    {
        public bool CanHandle(Message theMessage, Configuration theConfiguration)
        {
            return theMessage.BatchSize == 1;
        }
    }

    public class HandlesOneInsert : IComponent
    {
        public bool CanHandle(Message theMessage, Configuration theConfiguration)
        {
            return theMessage.BatchSize == 1 && theMessage.Action = "Insert";
        }
    }

1 つのレコードの挿入メッセージが 2 番目のレコードを選択する必要があることをシステムに知らせたいのは、それが最も具体的なレコードだからです。現時点では、さまざまな優先度レベルを設定する必要がありますが、それでは扱いにくくなり、将来的に新しいコンポーネントを作成するときにバグが発生するように感じます。

明確化のために追加:
システムが思い通りに動作するようになった場合、「挿入」タイプのアクションを処理する2つのコンポーネントと、バッチサイズが「挿入」を処理する特定のコンポーネントを持つことができます。 = 1. コードを書く開発者は、システムが正しいものを選択することを気にする必要はありません。

ありがとう!

4

3 に答える 3

2

これは、スコアリング システムを使用して行うことができます。

public sealed class Score
{
    private int _score;

    public Score(params bool[] conditions)
    {
        foreach(bool b in conditions)
        {
           if(b)
              ++_score;
           else
           {
              _score = 0;
              break;
           }
        }
    } // eo ctor

    public int Total { get { return _score; } }
}  // eo class Score

次のIComponentようになります。

public interface IComponent
{
    Score CanHandle(Message theMessage, Configuration theConfiguration);
}  // eo IComponent

専門分野:

public class HandlesOneRecord : IComponent
{
    public Score CanHandle(Message theMessage, Configuration theConfiguration)
    {
        return new Score(theMessage.BatchSize == 1);
    }
}

public class HandlesOneInsert : IComponent
{
    public Score CanHandle(Message theMessage, Configuration theConfiguration)
    {
        return new Score(theMessage.BatchSize == 1, theMessage.Action == "Insert");
    }
}

次に、最も適切なハンドラーを見つけるために、反復処理を繰り返して、最大のスコアを持つハンドラーを選択します。何百ものハンドラーがある場合、 のハッシュ コードを生成し、Message成功したルックアップをDictionary<int, Func<Message, Configuration, Score>>.

于 2013-07-08T12:44:56.037 に答える
2

あなたのドメインはすでにかなりメッセージ指向であるため、 NServiceBusのようなある種のメッセージ バスを使用することを検討しましたか?

これらのタイプのインフラストラクチャには、タイプに基づいたハンドラーへのディスパッチ、ポリモーフィズム、ハンドラーの順序を定義する機能、各ハンドラーを停止できる機能など、探していると思われるメッセージ処理パイプラインがあります。パイプライン。

于 2013-07-08T12:34:32.847 に答える
0

タイプではなく、メッセージに含まれるデータに基づいてコンポーネントを選択したいようです。

仕様パターンは、優れた拡張可能なオプションになる可能性があります。ボブ・ホーンが提案したように、各コンポーネントが注入された仕様に基づいてメッセージを処理できるかどうかを判断する責任の連鎖を持つことができます。これらの行に沿った何か:

public abstract class Component 
{
  protected Component _next;
  protected MessageSpecification _specification;

  public Component(MessageSpecification specification)
  {
    // Inject specification here
  }

  public void Inspect(Message message)
  {
    if (_specification.IsSatisfiedBy(message))
    {
       Handle(message);
    }
    else _next.Inspect(message);
  }

  abstract void Handle(Message message);
}

システムの他の部分では、次のことを行う必要があります。

  • 各コンクリート コンポーネントと、関連する仕様がある場合はそれを定義します。

  • 責任の連鎖を特定の順序で組み立てます。これは、ドメイン ルール (あなただけが知っている可能性があります) に基づいて実行するか、すべての仕様が相互に排他的であると仮定して、すべての仕様ベースのコンポーネントをチェーンの最初に配置することによって実行できます。

于 2013-07-08T10:59:33.877 に答える