最初に、インターフェースを公開して、集約ルート (すなわち Order()) への参照を取得する必要があります。Factory パターンを使用して、Aggregate Root (つまり Order()) の新しいインスタンスを新しく作成します。
そうは言っても、集約ルートのメソッドは、それ自体ではなく、関連するオブジェクトへのアクセスを制御します。また、複合型を集約ルート (つまり、例で述べた Lines() IList コレクション) で public として公開しないでください。これは、Order.Lines.Add() などのメソッドに「ドット ウォーク」することはできないという減分率 (sp ck) の法則に違反しています。
また、クライアントが集約ルート上の内部オブジェクトへの参照にアクセスすることを許可する規則にも違反しています。集約ルートは、内部オブジェクトの参照を返すことができます。限り、外部クライアントはそのオブジェクトへの参照を保持できません。つまり、RemoveLine() に渡す「OrderLine」です。外部クライアントがモデルの内部状態 (つまり、Order() とその OrderLines()) を制御できるようにすることはできません。したがって、OrderLine はそれに応じて動作する新しいインスタンスであると想定する必要があります。
public interface IOrderRepository
{
Order GetOrderByWhatever();
}
internal interface IOrderLineRepository
{
OrderLines GetOrderLines();
void RemoveOrderLine(OrderLine line);
}
public class Order
{
private IOrderRepository orderRepository;
private IOrderLineRepository orderLineRepository;
internal Order()
{
// constructors should be not be exposed in your model.
// Use the Factory method to construct your complex Aggregate
// Roots. And/or use a container factory, like Castle Windsor
orderRepository =
ComponentFactory.GetInstanceOf<IOrderRepository>();
orderLineRepository =
ComponentFactory.GetInstanceOf<IOrderLineRepository>();
}
// you are allowed to expose this Lines property within your domain.
internal IList<OrderLines> Lines { get; set; }
public RemoveOrderLine(OrderLine line)
{
if (this.Lines.Exists(line))
{
orderLineRepository.RemoveOrderLine(line);
}
}
}
Order() の新しいインスタンスを作成するためのファクトリを忘れないでください。
public class OrderFactory
{
public Order CreateComponent(Type type)
{
// Create your new Order.Lines() here, if need be.
// Then, create an instance of your Order() type.
}
}
外部クライアントには、インターフェイスを介して IOrderLinesRepository に直接アクセスし、集約ルート内の値オブジェクトの参照を取得する権利があります。しかし、集約ルートのメソッドからすべての参照を強制することで、それをブロックしようとしています。したがって、上記の IOrderLineRepository を内部としてマークして、公開されないようにすることができます。
私は実際に、すべての Aggregate Root 作成物を複数の Factory にグループ化しています。「一部の集約ルートには複合型のファクトリがあり、他にはありません」というアプローチは好きではありませんでした。ドメイン モデリング全体で同じロジックに従う方がはるかに簡単です。「ああ、Sales() は Order() のような集約ルートです。それにもファクトリが必要です。」
最後に、SalesOrder() のように、Sales() と Order() の 2 つのモデルを使用する組み合わせがある場合、Service を使用して、SalesOrder() のインスタンスを作成し、Sales()または Order() Aggregate ルートも、そのリポジトリまたはファクトリも、SalesOrder() エンティティを制御します。
Abel Avram と Floyd Marinescu による Domain Drive Design (DDD) に関するこの無料の本は、100 ページの大きな活字であなたの質問に直接答えてくれるので、強くお勧めします。ドメインエンティティをモジュールなどにさらに分離する方法とともに。
編集:コードを追加