Chciałbym napisać aplikację podobną do e-commerce.
I wiesz, że w podobnych aplikacjach produkty mogą mieć różne właściwości i funkcje. Aby zasymulować taką możliwość, stworzyłem następujące podmioty modelu domeny:
Kategoria - jest to coś w rodzaju „elektronika> komputery”, czyli rodzaje produktów. Kategorie zawierają listę właściwości (Lista <Właściwość>).
Właściwość - niezależna jednostka, która zawiera nazwę, jednostki miary, typ danych. Na przykład „nazwa”, „waga”, „rozmiar ekranu”. Ta sama właściwość może mieć różne produkty.
Produkt - zawiera tylko nazwę i listę wartości odnoszących się do właściwości. Wartość to obiekt, który zawiera tylko pole wartości i identyfikator pola właściwości.
Pierwotnie zdecydowałem, aby kategoria była jak pojedynczy agregat w tym schemacie, ponieważ na przykład, gdy dodam nowy produkt, muszę znać wszystkie dane związane z bieżącą kategorią, w tym właściwości związane z bieżącą kategorią ( category.AddNewProduct (produkt) ). Ale co powinienem zrobić, gdy muszę tylko dodać nową właściwość, która nie należy do żadnej kategorii. Na przykład nie mogę zrobić tej kategorii.AddNewProperty (właściwość), ponieważ wyraźnie mówi, że dodajemy właściwość do określonej kategorii.
Ok, w następnym kroku postanowiłem rozdzielić Właściwość na osobny agregat, ale wtedy będzie to lista z prostymi jednostkami.
Oczywiście mogę stworzyć coś takiego jak PropertyAggregate, aby zachować wewnętrzną listę właściwości i reguł biznesowych, ale kiedy dodam produkt, muszę mieć wewnątrz kategorii całą listę właściwości należących do tej kategorii, aby sprawdzić niezmienniki. Ale zdaję sobie również sprawę, że trzymanie linków wewnątrz agregatu na innych agregatach jest złą praktyką.
Jakie są opcje zaprojektowania tego przypadku biznesowego?
Odpowiedzi:
W perspektywie DDD
Category
,Product
iProperty
są bytami: wszystkie odpowiadają obiektom, które mają własną tożsamość.Opcja 1: twój oryginalny projekt
Zrobiłeś
Category
korzeń jednego agregatu. Z jednej strony ma to sens, ponieważ łączna zapewnia spójność, gdy jej cele zostały zmodyfikowane, iProduct
musi miećProperties
ITSCategory
:Ale z drugiej strony pojedynczy agregat oznacza, że wszystkie jego obiekty są powiązane z katalogiem głównym, który jest ich właścicielem, a wszystkie odniesienia zewnętrzne muszą być dokonywane za pośrednictwem tego agregatu. To daje do zrozumienia ze:
Product
należy do jednego i tylko jednegoCategory
. JeśliCategory
zostanie usunięty, to i jegoProducts
.Property
należy do jednego i tylko jednegoCategory
. Innymi słowy, jeśli „ekrany telewizyjne” i „monitory komputerowe” byłyby dwiema kategoriami, „ekrany telewizyjne: rozmiar” i „monitory komputerowe: rozmiar” miałyby dwie różne właściwości.Drugi punkt nie odpowiada twojej narracji: „ Ale co powinienem zrobić, gdy muszę tylko dodać nowy
Property
, który nie należy do żadnej kategorii ”. I nie jest jasne, czy to samoProperties
można zastosować w inny sposóbCategories
.Opcja 2: Nieruchomość poza agregatem
Jeśli
Property
istnieje niezależnie odCategories
, musi znajdować się poza agregatem. I to samo, jeśli chcesz dzielićProperties
międzyCategories
(co ma sens dla wysokości, szerokości, rozmiarów itp.). Wydaje się, że tak właśnie jest.Konsekwencją jest powiązanie między
Property
rzeczami, które należą do agregatu: podczas gdy możesz nawigować z wnętrza agregatu doProperty
, nie możesz już przechodzić bezpośrednio od aProperty
do odpowiednich wartości. To ograniczenie żeglowności może być pokazane na diagramie UML:Zauważ, że ten projekt nie przeszkadza ci
List<Property>
wCategory
tworzeniu semantycznej referencji (np. Java): każda referencja na liście odnosi się doProperty
obiektu, który można współdzielić w repozytorium.Jedynym problemem związanym z tym projektem jest to, że można go zmienić
Property
lub usunąć: ponieważ jest on poza agregatem, agregat nie może zadbać o spójność jego niezmienników. Ale to nie jest problem. Jest to konsekwencja zasad DDD i złożoności świata rzeczywistego. Oto cytat Erica Evansa z jego przełomowej książki „ Domain-Driven Design: Tackling Complexity in the Heart of Software ”:Tak więc, jeśli zmienisz a
Property
, będziesz musiał upewnić się, że usługa sprawdza kategorie, które jej dotyczą, są aktualizowane w razie potrzeby.Opcja 3: kategoria, właściwość i produkt w różnych agregatach
Zastanawiam się tylko, czy założenie, że
Product
należy do singla,Category
jest uzasadnione:Product
pod kilkomaCategories
. Na przykład „Laptop Marka X Model Y” można znaleźć w kategorii „Laptopy” i kategoria „Komputery”, a „drukarka wielofunkcyjna Z” w kategorii „drukarka”, „skaner” i „faks”.Product
pierwszy, a dopiero później przypisze go do kategorii i wypełni wartości?Nie uprości to agregacji, a będziesz mieć jeszcze więcej reguł, które obejmują agregaty. Ale twój system byłby o wiele bardziej odporny na przyszłość.
źródło
Property
poza graniceCategory
agregatu, czy to oznacza, żeProperty
staje się ono agregatem i potrzebuje repozytorium? Jeśli to prawda, to jak przekazać wymaganeList<Property>
doCategory
instancji? Przez konstruktora? Będzie dobrze? I jak mogę znaleźć listęProperty
identyfikatorów,Category
które nie zostały jeszcze utworzone?Feature
która będzie należeć tylko doProduct
. i ten podmiot nie będzie uczestniczył w wyszukiwaniu. Co mówisz ?Moim zdaniem możesz to rozwiązać na dwa sposoby:
Kategoria to specjalny rodzaj produktu
Oznacza to, że dla każdego produktu w bazie danych zawiera klucz obcy wskazujący na ten sam produkt tabeli. Produkt jest produktem tylko wtedy, gdy nie ma produktów, których klucz obcy jest równy identyfikatorowi tego produktu. Innymi słowy, jeśli nie ma pod nim żadnych produktów, jest to produkt.
Uprościłoby to trochę. Produkty do właściwości miałyby relację jeden do wielu, a zatem również Twoje kategorie mają relację jeden do wielu, ponieważ są one również produktami. Dodanie właściwości do kategorii byłoby tak proste, jak dodanie właściwości do produktu w twoim programie. Wczytanie wszystkich właściwości oznaczałoby połączenie właściwości produktu z właściwościami powiązanego produktu kategorii i dalej, aż dojdziesz do kategorii produktu bez elementu nadrzędnego.
Twoja aplikacja e-commerce będzie musiała wprowadzić to rozróżnienie, ale jeśli mimo to prawdopodobnie załadujesz produkty kategorii, nie jest to strata wydajności, jeśli wiesz, czy masz do czynienia z kategorią lub produktem. Ładnie nadaje się również do wyszukiwania w stylu drzewa do poziomu produktu, ponieważ każdy produkt (kategoria) otworzyłby się na listę podproduktów bez większego nakładu pracy.
Wadą tego są oczywiście dodatkowe informacje obecne w produkcie, które nie mają sensu dla kategorii, powodowałyby niewygodne niewykorzystane pola w produkcie. Chociaż to rozwiązanie byłoby bardziej elastyczne w twojej aplikacji, jest również nieco mniej intuicyjne.
Relacja wiele do wielu
Produkty nie są już w złożonym związku z własnością. Tworzysz tabelę ProductProperty z kluczami obcymi zarówno tabeli produktu, jak i tabeli właściwości, które je łączą. Podobnie masz tabelę kategorii z relacją wiele do wielu z tabelą właściwości i tabelę CategoryProperty z kluczami obcymi zarówno tabeli kategorii, jak i tabeli właściwości.
Sam produkt miałby relację typu „jeden do jednego” z kategorią, umożliwiając zasadniczo utworzenie listy unikalnych właściwości dotyczących zarówno produktu, jak i kategorii za pomocą dobrze sformalizowanej instrukcji select.
Z punktu widzenia bazy danych jest to zdecydowanie czystsze i bardziej elastyczne. Twoja aplikacja prawdopodobnie wykona większość zadań bez bezpośredniego kontaktu z CategoryProperty lub ProductProperty, jeśli zapytanie zostanie wykonane poprawnie. Nie należy jednak traktować kategorii ani produktu jako właściciela nieruchomości. Powinien to być własny podmiot w twoim programie. Oznacza to również, że zarządzanie wymienionymi właściwościami byłoby kwestią utworzenia samej właściwości, a następnie powiązania jej z kategorią lub produktem w dwóch oddzielnych krokach. Z pewnością więcej pracy niż pierwsze rozwiązanie, ale bynajmniej nie trudniejsze.
Oprócz tego będziesz musiał przeprowadzić dodatkową kontrolę po usunięciu kategorii lub produktu, jeśli którakolwiek z jej właściwości jest wykorzystywana przez inne osoby (w przeciwieństwie do pierwszego rozwiązania, w którym możesz bezpiecznie wyeliminować wszystkie powiązane właściwości danego produktu / kategorii) .
Wniosek
W kontekście zawodowym wybrałbym kategorię dodatkowych mil i odległości od produktu i produktu od nieruchomości, stosując podejście wiele do wielu. Nie byłoby możliwości nakładania się danych iw pewnym sensie łatwiej jest uzasadnić każdą z tych trzech dziedzin jako własną całość. Jednak w żadnym wypadku pierwsze rozwiązanie nie jest złe, ponieważ pozwala także napisać prostszą aplikację. Po prostu wiedz, że jeśli pomyślałeś, że w końcu może zajść potrzeba przejścia z jednego rozwiązania na drugie, prawdopodobnie najlepszym rozwiązaniem byłoby wybranie drugiego.
Powodzenia!
źródło