Domanda

Given the following example aggregate:

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
    }
}

What is to prevent someone from going around the aggregate root and modifying the OrderLine directly? For example:

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

Is there anyway to have a truly encapsulated aggregate root? Would the only solution be to create a set of parallel order lines value objects that get exposed instead?

Thanks for any insight.

È stato utile?

Soluzione

Can't you start with making the Cancel method internal so it is only visible inside your Order assembly? Off course other classes in this assembly can then still access the cancel method.

Maybe another way is to expose the collection of OrderLines as a collection of IOrderLine interfaces and hide the Cancel method that way.

Altri suggerimenti

Why do you expose Lines? Expose some snapshot (DTO) containing information about OrderLines that you need outside but not OrderLines themselves. It's known solution. And with CQRS you may not need to expose it at all.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top