リポジトリパターンを適切に使用する方法を頭に入れようとしています。集約ルートの中心概念は今後も登場し続けます。集約ルートとは何かについて、WebとStack Overflowの両方を検索するとき、それらについての議論と、基本定義を含むはずのページへのデッドリンクを見つけ続けます。
リポジトリパターンのコンテキストでは、集約ルートとは?
リポジトリパターンのコンテキストでは、クライアントコードがリポジトリからロードするオブジェクトは集約ルートのみです。
リポジトリは、子オブジェクトへのアクセスをカプセル化します-呼び出し元の観点から、ルートがロードされるか、実際に必要なときに(遅延ロードの場合のように)自動的にロードします。
たとえば、複数のOrder
オブジェクトに対する操作をカプセル化するLineItem
オブジェクトがあるとします。クライアントコードはLineItem
オブジェクトを直接ロードすることはなく、それらを含むOrder
だけをロードします。これはドメインのその部分の集約ルートになります。
エヴァンスDDDから:
AGGREGATEは、データ変更の目的で1つの単位として扱う関連オブジェクトのクラスターです。各AGGREGATEには、ルートと境界があります。境界は、AGGREGATEの内部を定義します。ルートは、AGGREGATEに含まれる単一の特定のENTITYです。
そして:
ルートは、外部オブジェクトが[。]への参照を保持できるAGGREGATEの唯一のメンバーです。
これは、リポジトリからロードできるオブジェクトが集約ルートのみであることを意味します。
例は、Customer
エンティティとAddress
エンティティを含むモデルです。関連するAddress
のコンテキストなしでは意味をなさないため、モデルからCustomer
エンティティに直接アクセスすることはありません。したがって、Customer
とAddress
は一緒に集約を形成し、Customer
は集約ルートであると言えます。
集約ルートは、単純なアイデアの複雑な名前です。
適切に設計されたクラス図は、その内部をカプセル化します。この構造にアクセスするポイントは、aggregate root
と呼ばれます。
ソリューションの内部は非常に複雑かもしれませんが、この階層のユーザーはroot.doSomethingWhichHasBusinessMeaning()
を使用するだけです。
どのように車に乗りたいですか?より良いAPIを選択
オプションA(どういうわけか機能します):
car.ride();
オプションB(ユーザーはクラスinernalsにアクセスできます):
if(car.getTires().getUsageLevel()< Car.ACCEPTABLE_TIRE_USAGE)
for (Wheel w: car:getWheels()){
w.spin();
}
}
オプションAの方がおめでとうと思います。 aggregate root
の背後にある主な理由がわかります。
集約ルートは複数のクラスをカプセル化します。メインオブジェクトを介してのみ階層全体を操作できます。
コンピュータエンティティがあるとします。このエンティティは、ソフトウェアエンティティとハードウェアエンティティなしでは存続できません。これらは、Computer
集合体、ドメインのコンピューター部分のミニエコシステムを形成します。
アグリゲートルートはアグリゲート内のマザーシップエンティティです(この場合はComputer
)。レポジトリをアグリゲートルートであるエンティティでのみ動作させるのが一般的であり、このエンティティは他のエンティティの初期化を担当します。
Aggregate RootをAggregateへのエントリポイントとして検討します。
C#コードの場合:
public class Computer : IEntity, IAggregateRoot
{
public Hardware Hardware { get; set; }
public Software Software { get; set; }
}
public class Hardware : IEntity { }
public class Software : IValueObject { }
public class Repository<T> : IRepository<T> where T : IAggregateRoot {}
ハードウェアもValueObjectになる可能性があることに注意してください(独自にIDを持たないでください)。これは単なる例として考えてください。
データベース優先のアプローチに従う場合、集約ルートは通常、1対多の関係の1側にあるテーブルです。
最も一般的な例はPersonです。各人には、多くの住所、1つ以上の給与明細、請求書、CRMエントリなどがあります。常にそうとは限りませんが、9/10倍です。
現在、eコマースプラットフォームに取り組んでおり、基本的に2つの集約ルートがあります。
顧客は連絡先情報を提供し、トランザクションを割り当てます。トランザクションは広告申込情報を取得します。
販売者は、製品を販売したり、連絡を取り合ったり、当社についてのページや特別オファーなどを持っています。
これらは、それぞれ顧客リポジトリと販売者リポジトリによって処理されます。
Aggregateは何かのコレクションを意味します。
rootはツリーの最上位ノードに似ており、そこからWebページドキュメントの<html>
ノードなどのすべてにアクセスできます。
ブログのアナロジー、ユーザーは多くの投稿を持つことができ、各投稿は多くのコメントを持つことができます。したがって、ユーザーを取得すると、rootとして機能し、関連するすべての投稿とそれらの投稿のコメントにアクセスできます。これらはすべてまとめてコレクションまたはAggregatedと呼ばれます
アグリゲートは、アクセス思考アグリゲートルートを制限することで不変式を保護し、一貫性を強制します。集約は、データベースの関係ではなく、プロジェクトのビジネスルールと不変条件に基づいて設計する必要があることを忘れないでください。リポジトリを挿入しないでください。また、クエリは許可されません。
Erlangでは、OO構成ではなく、状態内のデータ構造によって集約が構成されると、集約を区別する必要はありません。例を参照してください: https://github.com/bryanhunter/cqrs-with-erlang/tree/ndc-london