Evans presenta en su libro "Diseño controlado por dominio" en el Capítulo 6 "Agregados" el concepto de Agregados. Además define las reglas para traducir ese concepto en una implementación (Evans 2009, pp. 128-129):
La ENTIDAD raíz puede entregar referencias a las ENTIDADES internas a otros objetos, pero esos objetos pueden usarlas solo de manera transitoria y es posible que no se aferren a la referencia.
Después de elaborar otras reglas, las resume en este párrafo:
Agrupe las entidades y los objetos de valor en agregados y defina límites alrededor de cada uno. Elija una entidad para que sea la raíz de cada agregado y controle todo el acceso a los objetos dentro del límite a través de la raíz. Permita que los objetos externos contengan referencias solo a la raíz. Las referencias transitorias a miembros internos pueden pasarse para su uso dentro de una sola operación solamente. Debido a que la raíz controla el acceso, los cambios en las partes internas no pueden dejarlo ciego. Esta disposición hace que sea práctico hacer cumplir todos los invariantes para los objetos en el Agregado y para el Agregado en su conjunto en cualquier cambio de estado.
Entonces, ¿qué significa exactamente el uso transitorio?
Mi colega entiende que solo la raíz agregada expone una interfaz pública para los clientes. Los clientes no tendrán la oportunidad de llamar a ninguna operación en una entidad que no sea la raíz agregada.
Mi comprensión de las oraciones citadas es diferente. Entiendo que, de hecho, permite explícitamente a los clientes llamar a operaciones en entidades internas. Sin embargo, solo después de obtenerlos desde la raíz.
Entonces, tengamos un ejemplo concreto:
Digamos que un Cart
consiste en muchos Items
. Cada uno Item
tiene un Quantity
. El modelo debe admitir el caso de uso "Aumentar la cantidad de un artículo específico". No se pueden violar invariantes que afecten cualquier cosa fuera del artículo.
¿Está violando un modelo las reglas citadas anteriormente, cuando un cliente puede hacer esto llamando cart.item(itemId).increaseQuantity()
o si un cliente solo puede llamar cart.increaseItemQuantity(itemId)
? ¿Cuál sería el beneficio de este último?
fuente
cart.increaseItemQuantity(itemId)
, si no por otra razón, es una violación menor de la Ley de Demeter. Llamar lecart.increaseItemQuantity(itemId)
permite hacer cosas como actualizar las cantidades totales del carrito.Respuestas:
Mientras
Item
no pueda existir sinCart
estar también presente, entonces no hay diferencia entre las dos opciones. Es posible mantener invariantes en ambos casos.En el caso de que el método esté activado
Item
,Item
puede "notificar" a su carrito principal para verificar el invariante cuando necesita cambiar su propio estado. Esto hace las cosas un poco más complicadas, porque entonces hay una dependencia cíclica entreItem
yCart
(lo que supongo que no es un problema gracias a la suposición en la primera oración y algo que la OMI debe existir de cualquier manera).En caso de que el método esté
Cart
activado, lo hace más simple, porque no hay necesidad deItem
hacer referenciaCart
. Pero lo complica porque ahora el método no solo verifica la invariabilidad y cambia el estado. Pero también debe asegurarse de que el artículo (o su ID) sea válido para estoCart
. En el otro caso, esto ya se maneja mediante un método que consulta el artículo dado del carrito.tl; dr; Ambas opciones tienen claras ventajas y desventajas y ninguna parece ser obviamente mejor o peor que otra.
fuente