Können Clients Methoden für andere Entitäten als den aggregierten Stamm aufrufen?

10

Evans führt in seinem Buch "Domain Driven Design" in Kapitel 6 "Aggregate" das Konzept der Aggregate ein. Er definiert ferner Regeln, um dieses Konzept in eine Implementierung umzusetzen (Evans 2009, S. 128-129):

Die Root-ENTITY kann Verweise auf die internen ENTITIES an andere Objekte übergeben, diese Objekte können sie jedoch nur vorübergehend verwenden, und sie halten möglicherweise nicht an der Referenz fest.

Nachdem er andere Regeln ausgearbeitet hat, fasst er sie in diesem Absatz zusammen:

Gruppieren Sie die Entitäten und Wertobjekte zu Aggregaten und definieren Sie jeweils Grenzen. Wählen Sie eine Entität als Stamm jedes Aggregats aus und steuern Sie den gesamten Zugriff auf die Objekte innerhalb der Grenze über den Stamm. Zulassen, dass externe Objekte nur Verweise auf das Stammverzeichnis enthalten. Vorübergehende Verweise auf interne Mitglieder können nur zur Verwendung innerhalb einer einzelnen Operation ausgegeben werden. Da der Root den Zugriff steuert, kann er nicht durch Änderungen an den Interna blind gemacht werden. Diese Anordnung macht es praktisch, alle Invarianten für Objekte im Aggregat und für das Aggregat als Ganzes bei jeder Zustandsänderung zu erzwingen.

Was bedeutet vorübergehende Nutzung genau?

Mein Kollege versteht, dass nur das aggregierte Stammverzeichnis eine öffentliche Schnittstelle für die Clients bereitstellt. Clients haben keine Möglichkeit, eine Operation für eine andere Entität als den aggregierten Stamm aufzurufen.

Mein Verständnis der zitierten Sätze ist anders. Ich verstehe, dass es tatsächlich explizit erlaubt, dass Clients Operationen an internen Entitäten aufrufen. Allerdings erst, nachdem man sie von der Wurzel bekommen hat.

Lassen Sie uns ein konkretes Beispiel geben:

Nehmen wir an, a Cartbesteht aus vielen Items. Jeder Itemhat eine Quantity. Das Modell sollte den Anwendungsfall "Erhöhen Sie die Menge eines bestimmten Artikels" unterstützen. Es konnten keine Invarianten verletzt werden, die etwas außerhalb des Gegenstands betreffen.

Verstößt ein Modell gegen die oben genannten Regeln, wenn ein Client dies durch einen Anruf tun kann, cart.item(itemId).increaseQuantity()oder sollte es einem Client nur gestattet sein, einen anzurufen cart.increaseItemQuantity(itemId)? Was wäre der Vorteil des letzteren?

Markus Malkusch
quelle
Welches ist aus geschäftlicher Sicht sinnvoller?
Robert Harvey
Es ist ein künstliches Beispiel. Meine Frage betrifft die Interpretation der beiden zitierten Absätze aus Evans Buch. Die Experten für künstliche Domänen würden jedoch davon sprechen, "die Menge eines Einkaufswagens zu erhöhen". Warenkorb, Artikel und Menge sind also Teil des UL.
Markus Malkusch
1
Ihr Beispiel ist nicht künstlicher als Evans 'Erlasse. Es könnte nützlich sein, darauf hinzuweisen, dass DDD eigentlich keine Programmiertechnik ist, obwohl es viele Leute gibt, die versuchen, es auf diese Weise zu verwenden.
Robert Harvey
Können Sie etwas mehr Text aus dem Buch teilen, damit Ihre körperlosen Zitate mehr Kontext haben?
Robert Harvey
2
Ja dank. Was Evans sagt, ist, dass Sie dem Aggregate Root erlauben sollten, seinen eigenen internen Zustand zu kontrollieren (eine gute Praxis für jede Klasse, wirklich). Es ist daher wahrscheinlich sinnvoller, dem Wagen zu erlauben, Mengenerhöhungen mit zu kontrollieren cart.increaseItemQuantity(itemId), wenn auch aus keinem anderen Grund, als wenn es sich weniger um einen Verstoß gegen das Demeter-Gesetz handelt. Durch Anrufen cart.increaseItemQuantity(itemId)können Sie beispielsweise die Gesamtbeträge des Warenkorbs aktualisieren.
Robert Harvey

Antworten:

2

Solange Itemes nicht existieren kann, ohne Cartauch anwesend zu sein, gibt es keinen Unterschied zwischen den beiden Optionen. In beiden Fällen können Invarianten beibehalten werden.

Wenn die Methode aktiviert ist Item, Itemkann sie den übergeordneten Warenkorb "benachrichtigen", um die Invariante zu überprüfen, wenn sie ihren eigenen Status ändern muss. Dies macht die Dinge etwas komplizierter, da dann eine zyklische Abhängigkeit zwischen Itemund besteht Cart(was meiner Meinung nach aufgrund der Annahme im ersten Satz und der Tatsache, dass IMO so oder so existieren muss, kein Problem darstellt).

CartWenn die Methode aktiviert ist, ist sie einfacher, da keine ItemReferenz erforderlich ist Cart. Aber es macht es kompliziert, weil die Methode jetzt nicht nur nach Invarianten sucht und den Zustand ändert. Es muss aber auch sichergestellt werden, dass der Artikel (oder seine ID) dafür gültig ist Cart. Im anderen Fall wird dies bereits durch eine Methode behandelt, die einen bestimmten Artikel aus dem Warenkorb abfragt.

tl; dr; Beide Optionen haben klare Vor- und Nachteile und keine scheint offensichtlich besser oder schlechter zu sein als andere.

Euphorisch
quelle