2

はじめに

この質問は、Aggregate Root 以外の Aggregate 内のエンティティがイベント生成動作を行う DDD および Event Sourcing に関するものです。

以下は、私が説明する状況の例です。ここでは、Aggregate 内の他のエンティティ内にいくつかのロジックをカプセル化したいと確信しています。これには、実際の例とそれが良いモデルであるかどうかに関する不信の停止が含まれる場合があります。:)

DeliveryRun車両が配達を実行するための移動である Aggregate Root (AR)をモデル化しようとしています。出発する前に、最新のDeliveryManifest. それの「最新性」は、ARによって定義された一貫性の境界DeliveryManifest内のエンティティであることを私に示唆しています。DeliveryRun

ここまでは大丈夫です。

これには Event Sourcing アプローチを使用しています。このアプローチは、Greg Youngによって教えられ、 Regalo ライブラリに実装されています。これは、AR ( DeliveryRun) に動作がない場合、実際にはエンティティを持たなくてもSalesOrderよいことを意味します (たとえば、 a は代わりに/SalesOrderLinesなどのイベントを記録するため、エンティティを持たない場合があります)。ItemsAddedItemsRemoved

ただし、 の周りにはいくつかのロジックがありDeliveryManifestます。具体的には、マニフェストが最初に要求された後、品目が配送に追加されるときに、新しいバージョンのマニフェストを作成する必要があります。これは、利用可能な最新のマニフェストがなければ、ドライバーが出発しないようにすることができることを意味します。

オブジェクト内のロジックをカプセル化するDeliveryManifest場合 (これはシリアル化および保存されません。イベント ソーシングを使用しており、AR ではありません)、どうすればイベントをキャプチャできますか?

検討中のオプション

  • イベントはエンティティによって生成されますが、DeliveryManifestエンティティ自体に対して保存されますか (イベント ストアからロードさDeliveryRunれたときに、これらのイベントを に再生する方法を知る必要があります)。DeliveryManifest

  • (おそらくデータ構造を除いて)存在せずDeliveryManifest、すべてのロジック/イベントは によって直接実装されるべきDeliveryRunですか?

  • DeliveryManifestそれは独自の AR でDeliveryRunあり、現在のマニフェストの ID が通知されていることを確認する必要がありますか? これにより、マニフェスト オブジェクトが の一貫性の境界の外にあるため、マニフェストに関連するDeliveryRunの変更をサブスクライブするためのイベント処理を構築して、DeliveryRunそれに応じて更新/無効化などを行う必要があります。

  • Udi の DomainEvents パターンと同様に、イベントをキャプチャするための別のスタイルを実装します。これは、Regalo ライブラリを変更することを意味しますが、両方のパターンをかなり簡単にサポートできるようにすることができると思います。これにより、集約内のすべてのエンティティによって生成されたすべてのイベントをキャプチャできるため、AR に対して保存できます。ただし、ロード/再生の解決策を考える必要があります...

4

2 に答える 2

2

DeliveryManifest整合性の境界でない限り、別の集約ルートを作成することは避けます。

多くのサンプルはこの問題を扱っていません。内部のエンティティからイベントを収集し、後でロードするためにそれらを正しいエンティティに配布するのは集約ルートの責任であるように思われます。これはオプション1のようです。

オプション2は、に関連付けられた動作がない場合にも完全に適していDeliveryManifestます。

于 2013-02-08T12:23:12.840 に答える
0

メカニクスの答えは・・・バリエーションをたくさん思いつくところです。基本的に、誰がこれらすべてのイベントを収集するかを決定する必要があります: ルート (ここに表示) または各エンティティ (ここには表示されていないアプローチ) を個別に収集します。技術的には、以下に示す観察動作 (Rx、ハンドコーディングされたメディエーターなどを考えてください) を実装するための多くのオプションがあります。インフラストラクチャ コードのほとんどをエンティティに表示しました (ここでは抽象化が欠落しています)。

public class DeliveryRun {
  Dictionary<Type, Action<object>> _handlers = new Dictionary<Type, Action<object>>();
  List<object> _events = new List<object>();

  DeliveryManifest _manifest;

  public DeliverRun() {
    Register<DeliveryManifestAssigned>(When);
    Register<DeliveryManifestChanged>(When);
  }

  public void AssignManifest(...) {
    Apply(new DeliveryManifestAssigned(...));
  }

  public void ChangeManifest(...) {
    _manifest.Change(...);
  }

  public void Initialize(IEnumerable<object> events) {
    foreach(var @event in events) Play(@event);
  }

  internal void NotifyOf(object @event) {
    Apply(@event);
  }

  void Register<T>(Action<T> handler) {
    _handlers.Add(typeof(T), @event => handler((T)@event));
  }

  void Apply(object @event) {
    Play(@event);
    Record(@event);
  }

  void Play(object @event) {
    Action<object> handler;
    if(_handlers.TryGet(@event.GetType(), out handler)) {
      handler(@event); //dispatches to those When methods
    }
  }

  void Record(object @event) {
    _events.Add(@event);
  }

  void When(DeliveryManifestAssigned @event) {
    _manifest = new DeliveryManifest(this);
    _manifest.Initialize(@event);
  }

  void When(DeliverManifestChanged @event) {
    _manifest.Initialize(@event);
  }
}

public class DeliveryManifest {
  Dictionary<Type, Action<object>> _handlers = new Dictionary<Type, Action<object>>();
  DeliveryRun _run;

  public DeliveryManifest(DeliveryRun run) {
    _run = run;
    Register<DeliveryManifestAssigned>(When);
    Register<DeliveryManifestChanged>(When);
  }

  public void Initialize(object @event) {
    Play(@event);
  }

  public void Change(...) {
    Apply(new DeliveryManifestChanged(...));
  }

  void Register<T>(Action<T> handler) {
    _handlers.Add(typeof(T), @event => handler((T)@event));
  }

  void Play(object @event) {
    Action<object> handler;
    if(_handlers.TryGet(@event.GetType(), out handler)) {
      handler(@event); //dispatches to those When methods
    }
  }

  void Apply(object @event) {
    _run.NotifyOf(@event);
  }

  void When(DeliveryManifestAssigned @event) {
    //...  
  }

  void When(DeliveryManifestChanged @event) {
    //...  
  }
}

PS私はこれを「頭から」コーディングしました。コンパイルエラーを許してください。

于 2013-02-08T21:29:56.640 に答える