Ich möchte eine Anwendung wie E-Commerce schreiben.
Und Sie wissen, dass Produkte in ähnlichen Anwendungen unterschiedliche Eigenschaften und Merkmale haben können. Um eine solche Gelegenheit zu simulieren, habe ich die folgenden Domänenmodellentitäten erstellt:
Kategorie - dies ist so etwas wie "Elektronik> Computer", dh Arten von Produkten. СKategorien enthalten eine Liste von Eigenschaften (Liste <Eigenschaft>).
Eigenschaftsunabhängige Entität, die den Namen, die Maßeinheiten und den Datentyp enthält. Zum Beispiel "Name", "Gewicht", "Bildschirmgröße". Dieselbe Eigenschaft kann unterschiedliche Produkte haben.
Produkt - enthält nur den Namen und eine Liste der Werte für Eigenschaften. Wert ist ein Objekt, das nur das Wertfeld und die Feld-ID der Eigenschaft enthält.
Ich habe ursprünglich beschlossen, die Kategorie in diesem Schema wie ein einzelnes Aggregat zu gestalten, da ich beispielsweise beim Hinzufügen eines neuen Produkts alle Daten zur aktuellen Kategorie kennen muss, einschließlich der Eigenschaften zur aktuellen Kategorie ( category.AddNewProduct (Produkt) ). Aber was soll ich tun, wenn ich nur eine neue Eigenschaft hinzufügen muss, die keiner Kategorie angehört? Zum Beispiel kann ich diese Kategorie nicht ausführen. AddNewProperty (Eigenschaft), da eindeutig angegeben ist, dass wir die Eigenschaft einer bestimmten Kategorie hinzufügen.
Ok, im nächsten Schritt habe ich eine separate Eigenschaft in ein separates Aggregat umgewandelt, aber dann wird es eine Liste mit einfachen Entitäten sein.
Natürlich kann ich so etwas wie PropertyAggregate erstellen, um die Liste der Eigenschaften und Geschäftsregeln beizubehalten, aber wenn ich ein Produkt hinzufüge, muss die gesamte Liste der zu dieser Kategorie gehörenden Eigenschaften in der Kategorie enthalten sein, um die Invarianten zu überprüfen. Mir ist aber auch bewusst, dass es eine schlechte Praxis ist, die Links innerhalb des Aggregats auf anderen Aggregaten zu belassen.
Welche Möglichkeiten gibt es, um diesen Business Case zu entwerfen?
Antworten:
In der DDD Sicht
Category
,Product
undProperty
sind Einheiten: sie alle entsprechen den Objekten , die ihre eigene Identität haben.Option 1: Ihr ursprüngliches Design
Sie haben
Category
die Wurzel eines einzelnen Aggregats erstellt. Auf der einen Seite ist dies sinnvoll, da das Aggregat Konsistenz gewährleisten soll , wenn seine Objekte geändert werden, undProduct
muss die habenProperties
seinerCategory
:Auf der anderen Seite bedeutet das einzelne Aggregat, dass alle seine Objekte mit einem Stamm verknüpft sind, dem sie gehören, und dass alle externen Verweise über diesen Aggregatstamm erfolgen müssen. Dies impliziert Folgendes:
Product
gehört zu einer und nur einerCategory
. Wenn dasCategory
gelöscht wird, ist es auch seinProducts
.Property
gehört zu einem und nur einemCategory
. Wenn "Fernsehbildschirme" und "Computermonitore" zwei Kategorien wären, wären "Fernsehbildschirme: Größe" und "Computermonitore: Größe" zwei verschiedene Eigenschaften.Der zweite Punkt entspricht nicht Ihrer Erzählung: " Aber was soll ich tun, wenn ich nur eine neue hinzufügen
Property
muss, die keiner Kategorie angehört? " Und es ist nicht klar, ob dasselbeProperties
in verschiedenen verwendet werden kannCategories
.Option 2: Eigenschaft außerhalb des Aggregats
Wenn a
Property
unabhängig von existiertCategories
, muss es außerhalb des Aggregats liegen. Und das Gleiche, wenn SieProperties
zwischen beiden teilen möchtenCategories
(was für Höhe, Breite, Größe usw. Sinn macht). Dies scheint definitiv der Fall zu sein.Die Konsequenz ist die Verknüpfung zwischen
Property
und Dingen, die zum Aggregat gehören: Während Sie vom Inneren des Aggregats zu navigieren könnenProperty
, dürfen Sie nicht mehr direkt von aProperty
zu den entsprechenden Werten wechseln. Diese Einschränkung der Navigationsfähigkeit kann in einem UML-Diagramm angezeigt werden:Beachten Sie, dass dieses Design nicht verhindert, dass Sie ein
List<Property>
InCategory
mit einer Referenzsemantik (z. B. Java) haben: Jede Referenz in der Liste verweist auf ein gemeinsam nutzbaresProperty
Objekt in einem Repository.Das einzige Problem bei diesem Entwurf besteht darin, dass Sie ein ändern
Property
oder löschen können: Da es sich außerhalb des Aggregats befindet, kann das Aggregat die Konsistenz seiner Invarianten nicht berücksichtigen. Das ist aber kein Problem. Es ist die Folge der DDD-Prinzipien und der Komplexität der realen Welt. Hier ein Zitat von Eric Evans in seinem wegweisenden Buch " Domain-Driven Design: Komplexität im Herzen von Software angehen ":Wenn Sie also a ändern
Property
, müssen Sie sicherstellen, dass ein Dienst überprüft, ob die darauf verweisenden Kategorien bei Bedarf aktualisiert werden.Option 3: Kategorie, Eigenschaft und Produkt in verschiedenen Aggregaten
Ich frage mich nur, ob die Annahme, dass a
Product
zu einer SingleCategory
gehört, begründet ist:Product
unter mehreren vorschlagenCategories
. Beispielsweise finden Sie "Laptop Marke X Modell Y" unter der Kategorie "Laptops" und der Kategorie "Computer" und einen "Multifunktionsdrucker Z" unter der Kategorie "Drucker", "Scanner" und "Fax".Product
erste erstellt und diese erst später Kategorien zuweist und die Werte ausfüllt?Die Aggregate werden dadurch nicht vereinfacht, und Sie hätten noch mehr Regeln, die sich über Aggregate erstrecken. Ihr System wäre jedoch viel zukunftssicherer.
quelle
Property
die Grenzen desCategory
Aggregats überschreite, bedeutet dies, dass esProperty
zu einem Aggregat für sich wird und ein Repository benötigt? Wenn es wahr ist, wie wird es dannList<Property>
in dieCategory
Instanz übergeben? Durch den Konstruktor? Es wird richtig sein? Und wie finde ich die Liste derProperty
IDs einesCategory
noch nicht erstellten heraus?Feature
und diese nur derProduct
. und diese Entität wird nicht an der Suche teilnehmen. Was sagst du ?Aus meiner Sicht können Sie dies auf zwei Arten lösen:
Kategorie ist eine spezielle Art von Produkt
Dies bedeutet, dass jedes Produkt in Ihrer Datenbank einen Fremdschlüssel enthält, der auf dasselbe Tabellenprodukt verweist. Ein Produkt ist nur dann ein Produkt, wenn keine Produkte vorhanden sind, deren Fremdschlüssel der ID des Produkts entspricht. Mit anderen Worten, wenn es keine Produkte enthält, ist es ein Produkt.
Dies würde die Dinge etwas vereinfachen. Produkte zu Immobilien haben eine Eins-zu-Viele-Beziehung, und daher haben auch Ihre Kategorien eine Eins-zu-Viele-Beziehung, da sie auch Produkte sind. Das Hinzufügen einer Eigenschaft zu einer Kategorie ist so einfach wie das Hinzufügen einer Eigenschaft zu einem Produkt in Ihrem Programm. Das Laden aller Eigenschaften würde bedeuten, dass die Eigenschaften des Produkts mit den Eigenschaften des zugehörigen Kategorieprodukts kombiniert werden, bis Sie ein Kategorieprodukt ohne übergeordnetes Produkt erreichen.
Ihre E-Commerce-Anwendung müsste diese Unterscheidung treffen. Wenn Sie jedoch wahrscheinlich Produkte einer Kategorie laden, ist es kein Leistungsverlust, zu wissen, ob es sich um eine Kategorie oder ein Produkt handelt. Es eignet sich auch gut für die Suche in Baumform auf Produktebene, da sich jedes Produkt (jede Kategorie) ohne viel zusätzlichen Aufwand für eine Liste von Unterprodukten öffnen würde.
Der Nachteil dabei ist natürlich, dass zusätzliche Informationen im Produkt vorhanden sind, die für eine Kategorie nicht sinnvoll sind und unangenehme, nicht verwendete Felder im Produkt erzeugen würden. Diese Lösung wäre in Ihrer Anwendung zwar flexibler, aber auch etwas weniger intuitiv.
Viele-zu-viele-Beziehung
Produkte stehen nicht mehr in einer zusammengesetzten Beziehung zum Eigentum. Sie erstellen eine ProductProperty-Tabelle mit Fremdschlüsseln sowohl der Produkttabelle als auch der Eigenschaftstabelle, die die beiden verknüpfen. Ebenso haben Sie eine Kategorietabelle mit einer Viele-zu-Viele-Beziehung zur Eigenschaftentabelle und eine CategoryProperty-Tabelle mit Fremdschlüsseln sowohl der Kategorietabelle als auch der Eigenschaftentabelle.
Das Produkt selbst hat eine Eins-zu-Eins-Beziehung zur Kategorie, sodass Sie im Wesentlichen eine Liste eindeutiger Eigenschaften erstellen können, die sich sowohl auf das Produkt als auch auf die Kategorie beziehen, und zwar über eine gut formalisierte select-Anweisung.
Aus Sicht der Datenbank ist dies definitiv sauberer und flexibler. Ihre Anwendung könnte wahrscheinlich größtenteils ohne direkte Bearbeitung von CategoryProperty oder ProductProperty auskommen, wenn die Abfrage ordnungsgemäß ausgeführt wird. Sie sollten jedoch weder Kategorie noch Produkt als Eigentümer von Eigentum behandeln. Es sollte eine eigene Entität in Ihrem Programm sein. Dies bedeutet auch, dass für die Verwaltung dieser Eigenschaften die Eigenschaft selbst erstellt und dann in zwei separaten Schritten einer Kategorie oder einem Produkt zugeordnet werden muss. Sicher mehr Arbeit als die erste Lösung, aber keineswegs schwieriger.
Darüber hinaus müssten Sie beim Löschen einer Kategorie oder eines Produkts eine zusätzliche Überprüfung durchführen, wenn eine der Eigenschaften von anderen verwendet wird (im Gegensatz zur ersten Lösung, bei der Sie alle zugehörigen Eigenschaften eines bestimmten Produkts / einer bestimmten Kategorie sicher entfernen könnten). .
Fazit
In einem professionellen Kontext würde ich die Kategorie Extrameile und Entfernung von Produkt und Produkt von Eigentum unter Verwendung des Viele-zu-Viele-Ansatzes wählen. Es gibt keine Möglichkeit einer Überlappung von Daten, und in gewissem Sinne ist es einfacher, jede dieser drei als ihre eigene Einheit zu begründen. Die erste Lösung ist jedoch keineswegs eine schlechte, da Sie damit auch eine einfachere Anwendung schreiben können. Wenn Sie dachten, Sie müssten möglicherweise irgendwann von einer Lösung zur anderen wechseln, wäre es wahrscheinlich nur in Ihrem Interesse, die zweite auszuwählen.
Viel Glück!
quelle