Evans introduz em seu livro "Domain Driven Design" no capítulo 6 "Agregados" o conceito de Agregados. Ele define ainda regras para traduzir esse conceito em uma implementação (Evans 2009, pp. 128-129):
A ENTITY raiz pode entregar referências às ENTITIES internas a outros objetos, mas esses objetos podem usá-las apenas de forma transitória e podem não se apegar à referência.
Depois de elaborar outras regras, ele as resume neste parágrafo:
Agrupe as entidades e objetos de valor em agregados e defina limites em torno de cada um. Escolha uma Entidade para ser a raiz de cada Agregado e controle todo o acesso aos objetos dentro do limite através da raiz. Permita que objetos externos mantenham referências apenas à raiz. Referências transitórias a membros internos podem ser distribuídas para uso somente em uma única operação. Como a raiz controla o acesso, ela não pode ser surpreendida por alterações nos internos. Esse arranjo torna prático aplicar todos os invariantes a objetos no agregado e ao agregado como um todo em qualquer alteração de estado.
Então, o que exatamente o uso transitório significa?
Meu colega entende que apenas a raiz agregada expõe uma interface pública para os clientes. Os clientes não terão oportunidade de chamar qualquer operação em uma entidade que não seja a raiz agregada.
Meu entendimento das frases citadas é diferente. Entendo que, de fato, permite explicitamente clientes chamar operações em entidades internas. No entanto, somente após obtê-los da raiz.
Então, vamos dar um exemplo concreto:
Digamos que um Cart
consiste em muitos Items
. Cada Item
um tem um Quantity
. O modelo deve suportar o caso de uso "Aumentar a quantidade de um item específico". Nenhum invariável pode ser violado, o que afeta algo fora do Item.
Um modelo está violando as regras acima citadas, quando um cliente pode fazer isso chamando cart.item(itemId).increaseQuantity()
ou um cliente deve ter permissão para chamar apenas um cart.increaseItemQuantity(itemId)
? Qual seria o benefício deste último?
cart.increaseItemQuantity(itemId)
, se por nenhuma outra razão, a menos que seja uma violação da Lei de Deméter. A chamada cart.increaseItemQuantity(itemId)
permite que você faça coisas como atualizar os valores totais do carrinho.