2014-02-20 51 views
0

考虑下面的例子合计:DDD - 子实体封装

public class Order 
{ 
    private readonly IList<OrderLine> _orderLines; 
    public IEnumerable<OrderLine> Lines { get { return _orderLines; } } 

    public Order() 
    { 
     _orderLines = new List<OrderLine>(); 
    } 

    public void AddOrderLine(string sku, int qty) 
    { 
     _orderLines.Add(new OrderLine(sku, qty)); 
    } 

    public void CancelOrderLine(string sku) 
    { 
     OrderLine line = _orderLines.FirstOrDefault(l => l.Sku == sku); 
     if (line == null) 
      return; 

     line.Cancel(); 
    } 
} 

public class OrderLine 
{ 
    public string Sku { get; private set; } 
    public int Qty { get; private set; } 

    public OrderLine(string sku, int qty) 
    { 
     Sku = sku; 
     Qty = qty; 
    } 

    public void Cancel() 
    { 
     // do some cancellation stuff 
    } 
} 

什么是防止有人从各地聚集根底部并直接修改订单行?例如:

foreach(OrderLine line in currentOrder.Lines) 
{ 
    line.Cancel(); 
} 

有无论如何有一个真正封装的聚合根?唯一的解决方案是创建一组平行订单行值对象,而不是暴露?

感谢您的任何见解。

回答

1

难道你不能从取消方法内部开始,因此它只能在订单组件中可见吗? 当然,这个程序集中的其他类也可以访问取消方法。

也许另一种方法是将OrderLines的集合公开为IOrderLine接口的集合并以这种方式隐藏Cancel方法。

+0

是的,我认为使内部的方法减少曝光,并可能会做到这一点。也被视为接口路由,但有人可以将结果转换回OrderLine对象并直接调用cancel方法。我知道这与偏执狂有关,但我想我想知道是否有一种“正确”的方式来做到这一点,提供真正的封装,或者我将不得不在这里妥协?如果我没有得到更好的答案,我会接受你的。感谢您的建议。 –

0

你为什么暴露行?公开一些快照(DTO),其中包含有关OrderLines的信息,但您不需要OrderLines。这是已知的解决方案。而用CQRS你可能根本不需要暴露它。

+0

从我读过的书中可以看出DTO在这个领域本身没有地位。为我的所有子实体创建快照对象也非常繁琐。在附注中,我发现返回这样的列表:public IEnumerable Lines {get {return _orderLines.AsEnumerable(); }}解决了这个问题。修改返回的行不会影响聚合中存储的行。似乎是一个副本,而不是。 –