首先,您应该公开接口以获取对聚合根的引用(即 Order())。使用工厂模式来新建聚合根的新实例(即 Order())。
话虽如此,您的 Aggregate Root 上的方法控制对其相关对象的访问 - 而不是自身。此外,切勿在聚合根(即您在示例中说明的 Lines() IList 集合)上公开复杂类型。这违反了减量法则 (sp ck),即您不能“点走”您的方法,例如 Order.Lines.Add()。
而且,您违反了允许客户端访问对聚合根上的内部对象的引用的规则。聚合根可以返回内部对象的引用。只要不允许外部客户端持有对该对象的引用。即,您传递给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 标记为内部的,这样它就不会暴露。
我实际上将我所有的聚合根创建分组到多个工厂中。我不喜欢“一些聚合根将拥有复杂类型的工厂,而另一些则没有”的方法。在整个领域建模中遵循相同的逻辑要容易得多。“哦,所以 Sales() 是像 Order() 一样的聚合根。它也必须有一个工厂。”
最后一点是,如果有一个组合,即 SalesOrder(),它使用 Sales() 和 Order() 两种模型,您将使用服务来创建和操作该 SalesOrder() 实例,而不是 Sales()或 Order() 聚合根,也不是它们的存储库或工厂,拥有对 SalesOrder() 实体的控制权。
我强烈推荐这本由 Abel Avram 和 Floyd Marinescu 撰写的关于域驱动设计 (DDD) 的免费书籍,因为它以 100 页的大字体直接回答了您的问题。以及如何将您的域实体更多地解耦为模块等。
编辑:添加更多代码