Pojedyncza odpowiedzialność (powód zmiany) bytu powinna polegać na jednoznacznej identyfikacji, innymi słowy, jego odpowiedzialność musi być możliwa do odnalezienia.
Książka DDD Erica Evana, str. 93:
najbardziej podstawową odpowiedzialnością jednostek jest ustanowienie ciągłości, aby zachowanie było jasne i przewidywalne. Robią to najlepiej, jeśli są zachowani. Zamiast skupiać się na atrybutach, a nawet na zachowaniu, usuń definicję obiektu Entity do najbardziej nieodłącznych cech, szczególnie tych, które go identyfikują lub są powszechnie używane do jego znalezienia lub dopasowania. Dodaj tylko takie zachowanie, które jest niezbędne do pojęcia i atrybutów wymaganych przez to zachowanie.
Poza tym, spróbuj usunąć zachowanie i atrybuty do innych obiektów powiązanych z istotą Istotą. Poza problemami z tożsamością, Istoty mają tendencję do wypełniania swoich obowiązków poprzez koordynację operacji obiektów, których są właścicielami.
1.
... zredukuj definicję obiektu ENTITY do najbardziej nieodłącznych cech, szczególnie tych, które go identyfikują lub są powszechnie używane do jego znalezienia lub dopasowania. Dodaj tylko takie zachowanie, które jest niezbędne do koncepcji ...
Gdy jednostce zostanie przypisany unikalny identyfikator , jej tożsamość zostanie ustalona, więc zakładam, że taka jednostka nie potrzebuje żadnego zachowania, aby zachować swoją tożsamość lub pomóc w identyfikacji . Dlatego nie rozumiem, do jakiego zachowania autor odnosi się (oprócz find
i match
operacji ) z „ zachowaniem, które jest niezbędne dla koncepcji ”?
2)
... zredukuj definicję obiektu ENTITY do najbardziej nieodłącznych cech, szczególnie tych, które go identyfikują lub są powszechnie używane do jego znalezienia lub dopasowania. ... Poza tym, spróbuj usunąć zachowanie i atrybuty do innych obiektów powiązanych z podstawową ENTITY.
Więc każde zachowanie, które nie pomaga zidentyfikować bytu, ale nadal charakteryzowalibyśmy to zachowanie jako nieodłączną cechę tego bytu (tj. Szczekanie jest nieodłączne dla psów, latanie jest nieodłączne dla samolotów, składanie jaj jest nieodłączne dla ptaków. .), należy umieścić w innych obiektach związanych z tym bytem (przykład: powinniśmy umieścić zachowanie szczekania w obiekcie powiązanym z bytem)?
3)
Poza tym, spróbuj usunąć zachowanie i atrybuty do innych obiektów powiązanych z podstawową ENTITY.
a) MyEntity
przekazuje obowiązki A_resp
i B_resp
obiekty a
oraz b
odpowiednio.
Mimo że większość A_resp
i B_resp
praca jest wykonywana przez a
i b
instancje, klienci są nadal obsługiwani A_resp
i B_resp
przez MyEntity
, co oznacza, że z punktu widzenia klienta do tych dwóch obowiązków należą MyEntity
. Tak więc, nie to oznacza MyEntity
również ma A_resp
i B_resp
obowiązki i jako takie narusza SRP ?
b) Nawet jeśli założymy, że A_resp
i B_resp
nie należą do MyEntity
, MyEntity
nadal ma obowiązek AB_resp
koordynowania operacji obiektów a
i b
. Czyli nie MyEntity
narusza SRP, ponieważ ma przynajmniej dwa obowiązki - jednoznaczna identyfikacja, a także AB_resp
?
class MyEntity
{
private A a = ...
private B b = ...
public A GetA()
{ ... }
public B GetB()
{ ... }
/* coordinates operations of objects a and b */
public int AworkB()
{ ... }
}
/* A encapsulates a single responsibility resp_A*/
/* A is value object */
class A
{ ... }
/* B encapsulates a single responsibility resp_B*/
/* B is value object */
class B
{ ... }
AKTUALIZACJA:
1.
Zachowanie w tym kontekście odnosi się do zachowania semantycznego. Na przykład właściwość w klasie (tj. Atrybut w obiekcie domeny), która jest używana do jednoznacznej identyfikacji, ma zachowanie. Chociaż nie jest to bezpośrednio reprezentowane w kodzie. Oczekiwane zachowanie polega na tym, że dla tej właściwości nie będzie żadnych zduplikowanych wartości.
Tak więc w kodzie prawie nigdy nie musielibyśmy faktycznie wdrażać zachowania (tj. Operacji), które w jakiś sposób utrzymywałoby tożsamość jednostki, ponieważ jak wyjaśniono, takie zachowanie istnieje tylko jako koncepcja w modelu domeny (w postaci atrybutu ID encja), ale kiedy tłumaczymy ten atrybut ID na kod, część jego semantyki jest tracona (tj. część, która pośrednio upewnia się, że wartość identyfikatora jest unikalna, zostaje utracona)?
2)
Ponadto właściwość taka jak Wiek nie ma kontekstu poza bytem osobowym i jako taka nie ma sensu przenosić się do innego obiektu ... Jednak informacje te można łatwo przechowywać w osobnym miejscu, w którym unikalny identyfikator, stąd mylące odniesienie do zachowania. Wiek może być leniwie ładowaną wartością.
a) Jeśli Age
właściwość jest leniwie ładowana, możemy nazwać to zachowaniem, nawet jeśli semantycznie Age
jest tylko atrybutem?
3)
Możesz łatwo wykonać operacje specyficzne dla adresu, takie jak sprawdzenie, czy jest to prawidłowy adres. Być może nie wiesz tego w czasie projektowania, ale cała ta koncepcja polega na rozbiciu obiektów na ich najmniejsze części
Chociaż zgadzam się, że stracilibyśmy kontekst, przenosząc się Age
do innego obiektu, kontekst nie zostałby utracony, gdybyśmy przenieśli DateOfBirth
własność do innego obiektu, ale zwykle nie przenosimy go.
Jaki jest główny powód przejścia Address
do innego obiektu, ale nie DateOfBirth
? Ponieważ DateOfBirth
jest bardziej nieodłączny od Person
bytu lub ponieważ istnieje mniejsze szanse, że gdzieś w przyszłości będziemy musieli zdefiniować operacje specyficzne dla DateOfBirth
?
4. Muszę powiedzieć, że nadal nie wiem, czy MyEntity
ma też A_resp
i B_resp
obowiązki i dlatego MyEntity
też że AB_resp
nie jest uważana za naruszenie SRP
EULERFX
1)
Zachowania, o których mówi autor, są zachowaniami powiązanymi z bytem. Są to zachowania, które modyfikują stan bytu
a) Jeśli dobrze cię rozumiem, mówisz, że byt powinien zawierać tylko te zachowania, które modyfikują jego atrybuty (tj. jego stan )?
b) A co z zachowaniami , które niekoniecznie modyfikują stan bytu , ale nadal są uważane za nieodłączną cechę tego bytu (przykład: szczekanie byłoby nieodłączną cechą Dog
bytu, nawet gdyby nie zmodyfikował Stan psa )? Czy powinniśmy włączyć te zachowania do bytu, czy też należy je przenieść do innych obiektów?
2)
Jeśli chodzi o przenoszenie zachowania na inne obiekty, autor odnosi się konkretnie do obiektów wartości.
Chociaż mój cytat tego nie zawiera, ale autor wspomina w tym samym akapicie, że w niektórych przypadkach zachowania (i atrybuty ) zostaną przeniesione również do innych bytów (chociaż rozumiem korzyści płynące z przeniesienia zachowań na VO)
3) Zakładając, że MyEntity
(patrz pytanie 3. w moim oryginalnym poście) nie narusza SRP, czy powiedzielibyśmy, że odpowiedzialność za MyEntity
to obejmuje między innymi:
za. A_resp
+ B_resp
+ AB_resp
( AB_resp
współrzędne obiektów a
i b
)
lub
b. AB_resp
+ delegowanie A_resp
i B_resp
do obiektów ( a
i b
) powiązanych z MyEntity
?
4) Książka DDD Erica Evana, str. 94:
CustomerID to jedyny identyfikator PODMIOTU Klienta (rysunek 5.5), ale numer telefonu i adres byłyby często używane do znalezienia lub dopasowania Klienta. Nazwa nie określa tożsamości osoby, ale często jest używana jako część sposobu jej ustalenia.
W tym przykładzie atrybuty telefonu i adresu zostały przeniesione do klienta, ale w prawdziwym projekcie wybór ten zależałby od tego, w jaki sposób klienci domeny są zazwyczaj dopasowywani lub wyróżniani. Na przykład jeśli klient ma wiele kontaktowych numerów telefonów do różnych celów, to numer telefonu nie jest powiązany z tożsamością i powinien pozostać w kontakcie sprzedaży.
za)
CustomerID to jedyny identyfikator PODMIOTU Klienta (rysunek 5.5), ale numer telefonu i adres byłyby często używane do znalezienia lub dopasowania Klienta. Nazwa nie określa tożsamości osoby, ale często jest używana jako część sposobu jej ustalenia.
Cytat stwierdza, że tylko atrybuty związane z tożsamością powinny pozostać w encji . Zakładam, że autor oznacza, że encja powinna zawierać tylko te atrybuty, które są często używane do znalezienia lub dopasowania tej encji , podczas gdy WSZYSTKIE inne atrybuty powinny zostać przeniesione?
b) Ale w jaki sposób / gdzie należy przenieść inne atrybuty ? Na przykład (tutaj założenie jest takie, że atrybut adresu nie jest używany do znajdowania ani dopasowywania, Customer
dlatego chcemy usunąć atrybut adresu z Customer
):
jeśli zamiast mieć Customer.Address
(typu string
) tworzymy właściwość Customer.Address
typu Address
, to czy przenieśliśmy atrybut adresu do powiązanego obiektu VO (który jest typu Address
) czy powiedzielibyśmy, że Customer
nadal zawiera atrybut adresu ?
do)
W tym przykładzie atrybuty telefonu i adresu zostały przeniesione do klienta, ale w prawdziwym projekcie wybór ten zależałby od tego, w jaki sposób klienci domeny są zazwyczaj dopasowywani lub wyróżniani. Na przykład jeśli klient ma wiele kontaktowych numerów telefonów do różnych celów, to numer telefonu nie jest powiązany z tożsamością i powinien pozostać w kontakcie sprzedaży.
Autor nie ma racji tutaj, ponieważ jeśli założymy, że każdy z wielu kontaktowych numerów telefonów, które Customer
należą tylko do tego konkretnego Customer
, powiedziałbym, że te numery telefonów są powiązane z tożsamością tak samo, jak wtedy, gdy Customer
miał tylko jeden numer telefonu ?
5)
Powodem, dla którego autor sugeruje usunięcie jednostki, jest to, że kiedy początkowo tworzy się jednostkę klienta, istnieje tendencja do zapełniania jej dowolnym atrybutem, który można by pomyśleć o powiązaniu z klientem. Jest to podejście skoncentrowane na danych, które pomija zachowania, które ostatecznie prowadzą do anemicznego modelu domeny.
Off topic, ale myślałem, anemiczny model domeny wyników przesuwaniu zachowanie się o jednostkę , a Twój przykład jest zapełnianie się podmiot z wieloma atrybutami , które spowodowałyby Customer
zbyt wiele zachowań (odkąd prawdopodobnie także w Customer
tych zachowań , które zmodyfikować te dodatkowe atrybuty ), a tym samym naruszając SRP?
dzięki
Odpowiedzi:
Zachowanie w tym kontekście odnosi się do zachowania semantycznego. Na przykład właściwość w klasie (tj. Atrybut w obiekcie domeny), która jest używana do jednoznacznej identyfikacji, ma zachowanie. Chociaż nie jest to bezpośrednio reprezentowane w kodzie. Oczekiwanym zachowaniem jest to, że dla tej właściwości nie będzie żadnych zduplikowanych wartości. Coś takiego jak adres, który może mieć własną tożsamość, ale nie istnieje poza kontekstem bytu osobowego, nadal powinien zostać przeniesiony do własnego obiektu. W ten sposób promując Entity do zagregowanego katalogu głównego.
Ponadto właściwość taka jak Wiek nie ma kontekstu poza bytem osobowym i jako taka nie ma sensu przenosić się do innego obiektu. Kontekst zostałby utracony, a zatem można bezpiecznie stwierdzić, że jest to wartość, która jest niezbędna dla Istoty Osoby. W przeciwnym razie nie można znaleźć wartości. Jednak informacje te można łatwo przechowywać w osobnym miejscu, w którym znajduje się unikalny identyfikator, stąd mylące odniesienie do zachowania . Wiek może być leniwie ładowaną wartością.
Aby odpowiedzieć na twoje pytanie. Nie, nie narusza to zasady pojedynczej odpowiedzialności. Mówi się jedynie, że Osoba powinna mieć tylko rzeczy osobiste, a nie coś takiego jak Adres, który jest bardziej złożony i powiązany z osobą, powinien istnieć jako jej własny byt.
Możesz łatwo wykonać operacje specyficzne dla adresu, takie jak sprawdzenie, czy jest to prawidłowy adres. Być może nie wiesz tego w czasie projektowania, ale cała ta koncepcja polega na rozbiciu obiektów na ich najmniejsze części, aby coś takiego było względnie proste, gdy zrobiono to po fakcie.
Aktualizacja: 1) W większości przypadków weryfikacja tożsamości odbywa się po zapisaniu obiektu w magazynie danych. Co oznacza, że kod reprezentujący sprawdzanie poprawności encji istnieje, ale istnieje gdzie indziej. Zwykle istnieje z kodem odpowiedzialnym za wydanie wartości tożsamości. Dlatego stwierdzam, że unikalność nie jest reprezentowana bezpośrednio w kodzie encji.
2) Prawidłowe stwierdzenie to taki,
Age
który ma zachowanie. Musisz udokumentować fakt, że Age jest leniwie załadowany, aby deweloper korzystający z tej nieruchomości mógł podjąć dokładną decyzję dotyczącą sposobu korzystania z tej nieruchomości3)
DateOfBirth
zwykle jest innym przedmiotem; Obiekt daty, który ma już na nim predefiniowane operacje. W niektórych językach obiekt daty ma już zdefiniowany cały model domeny. Na przykład w c # możesz określić strefę czasową, jeśli data to UTC, dodaj i odejmij daty, aby uzyskać przedział czasowy. Więc twoje przypuszczenie o przeprowadzceDateOfBirth
byłoby prawidłowe.4) Jeśli jedyne, co
MyEntity
robi, to przekazywanie uprawnień i koordynacja, to nie, nie narusza to SRP. Jego jedynym obowiązkiem jest delegowanie i koordynowanie i jest określany jako wzór elewacjiźródło
Bardzo dobre pytanie. SRP nie należy brać tak dosłownie. Identyfikacja / wyszukiwanie nie jest obowiązkiem jednostki w odniesieniu do SRP. Ktoś inny jest odpowiedzialny za nadanie mu identyfikatora (mianowicie sklepu) i wyszukiwanie go (mianowicie repozytorium ).
Głównym celem bytu jest reprezentowanie pojęć odkrytych przez model. Jedyna różnica między Jednostką a Obiektem Wartości polega na tym, że Istota ma znaczenie wykraczające poza jej atrybuty nieidentyfikujące. Na przykład, jeśli osoba zmieni swoje imię, nadal jest tą samą osobą, tylko z innym imieniem.
źródło
TL; DR: już o tym myślisz. Jednak dobrze się bawiłem, zastanawiając się nad tym wraz z tobą. Więc zapnij pasy ....
Nie, to nie w porządku. Jedyną odpowiedzialnością jednostki jest ciągłość.
Tożsamość jest wyłaniającą się konsekwencją ciągłości. Modelowanie tożsamości jako oddzielnego pomysłu jest optymalizacją wydajności.
Oto przykład: Patronem restauracji daje samochód lokajowi. Godzinę później patron restauracji prosi o samochód. Czy kamerdyner powinien to dać?
Łatwo powiedzieć, że lokaj powinien dać samochód, jeśli patron jest „ten sam”. Ale co to tak naprawdę oznacza? Właściwy sposób, aby to ustalić, to zacząć od patrona „teraz” i przeszukać historię tego patrona, aby sprawdzić, czy oddanie samochodu lokajowi jest częścią tej historii.
Oczywiście nie możemy tego zrobić. Mamy problem z precyzyjnym śledzeniem własnej historii, nie wspominając o historii czegoś, co nie było z nami przez cały czas. Zamiast więc korzystać z historii patrona, robimy skróty. Czy patron posiada odcinek biletu, który ma ten sam numer co znacznik obecnie związany z kluczami? Czy prawo jazdy w portfelu patrona odpowiada nazwie na tytule w DMV, czy zdjęcie na prawie jazdy przypomina twarz patrona. Itp.
W skrócie: zamiast sprawdzać historię patrona, sprawdzamy aktualny stan patrona, aby sprawdzić, czy obecny stan jest zgodny z historią obejmującą okres między przybyciem samochodu a prośbą o jego zwrot.
Podczas modelowania jednostek korzystamy z analogicznej optymalizacji. Dajemy wszystkim podmiotom wspólną odpowiedzialność
Nie opisuję tutaj drugiej odpowiedzialności bytu; byt jest nadal odpowiedzialny za ciągłość - upewniając się, że historia jest spójną narracją. Obowiązki związane z identyfikatorem to tylko podzbiór, który jest wspólny dla wszystkich jednostek.
Nie mamy jeszcze żadnego wymuszenia wyjątkowości. Nie jest to możliwe w obrębie pojedynczego bytu, ponieważ wyjątkowość wymaga dostępu do stanu wszystkich bytów; gdzie jeden podmiot ma dostęp tylko do swojego.
Po raz kolejny sprawdzanie wszystkich identyfikatorów za każdym razem jest niepraktyczne, dlatego w prosty sposób zaspokajamy unikalność: kod, który generuje następny identyfikator, nigdy nie może się powtarzać.
W końcu oznacza to, że możemy zweryfikować ciągłość, testując równoważność dwóch różnych fragmentów stanu w pamięci, oszczędzając wiele kłopotów z próbą przeszukiwania wykresów acyklicznych.
Wygląda na to, że pomyliłeś zasadę pojedynczej odpowiedzialności (co jest naprawdę dobrym pomysłem) z zasadą odpowiedzialności atomowej. Podział odpowiedzialności na mniejsze, łatwiejsze do zarządzania części jest zgodny z SRP.
źródło
Jeśli tożsamość zostanie ustalona, to tak, jednostka nie potrzebuje niczego więcej do zidentyfikowania. Zachowania, o których mówi autor, są zachowaniami powiązanymi z bytem. Są to zachowania, które modyfikują stan bytu. Na przykład
Customer
jednostka możeMakePreferred
zachowywać się. Powodem, dla którego autor sugeruje usunięcie jednostki, jest to, że kiedyCustomer
jednostka początkowo tworzy jednostkę, istnieje tendencja do zapełniania jej dowolnym atrybutem, który można by pomyśleć o powiązaniu z klientem. Jest to podejście skoncentrowane na danych, które pomija zachowania, które ostatecznie prowadzą do anemicznego modelu domeny.Jeśli chodzi o przenoszenie zachowania na inne obiekty, autor odnosi się konkretnie do obiektów wartości. Powodem, dla którego warto przenieść zachowanie na VO, jest to, że VO są zwykle „mniejsze” niż byty, przez co są bardziej skoncentrowane. Co więcej, aspekty takie jak niezmienność i zamykanie operacji upraszczają rozumowanie na temat kodu, jednocześnie czyniąc go bardziej SOLIDNYM .
Razem z Lektorami jednostka służy jako rodzaj kotwicy, która koordynuje różne LISTY, które realizują swoje zachowanie.
Jeśli chodzi o SRP, twoje zamieszanie nie jest nieuzasadnione. Jednym ze problemów związanych ze stereotypowym wdrażaniem OOP podmiotów jest połączenie tożsamości i stanu. Rzeczywiście, z perspektywy behawioralnej tożsamość nie ma nic wspólnego z zachowaniami. Innymi słowy, tożsamość bytu nie jest wymagana dla żadnego z jego zachowań. Istnieją implementacje, w których eliminuje się to połączenie, takie jak AggregateSource lub funkcjonalne podejście, które tu opisuję .
Innym problemem jest to, że do pewnego stopnia SRP może być miarą jakościową. Każdy może wymyślić definicję pojedynczej odpowiedzialności, którą narusza niektóre klasy. Można powiedzieć, że obowiązkiem jednostki jest wdrożenie zachowań wymaganych od tej jednostki. W tym sensie ma jedną odpowiedzialność. Ponadto, gdy jednostka deleguje zachowania do składowych Lektorów, nie narusza to SRP. SRP nie zabrania tego rodzaju kompozycji. Ostrzega się, aby zredukować sprzężenie między obiektami do absolutnego minimum, zachować interfejsy tak gołe, jak to możliwe, itp.
AKTUALIZACJA
Tak, choć są wyjątki ...
Dopuszczalne jest, aby encje zawierały fabryczne metody tworzenia instancji encji, które byłyby enancjami potomnymi, ale gdzie odwołania do obiektów nie są używane do przejścia. W takim przypadku jednostka potomna musi zostać utrwalona przez usługę aplikacji. Usługa aplikacji używa encji nadrzędnej do utworzenia encji podrzędnej.
Patrzysz na odpowiedzialność z perspektywy wdrożenia. Zamiast tego rozważ jednostkę jako rodzaj czarnej skrzynki z obowiązkami. To, jak sobie z nimi radzi, nie jest dla ciebie interesujące, ponieważ ktoś patrzy z zewnątrz. Podział obowiązków między VO, a nawet inne podmioty stanowi problem wykonawczy.
Mówiąc dokładniej, atrybuty, które nie są wymagane do zachowania ani wyszukiwania, nie powinny być częścią bytu. Po co się męczyć? Co więcej, przy czymś takim jak wzorzec modelu odczytu , byty nie potrzebują niczego poza atrybutami wymaganymi do zachowania.
Tak, w efekcie nie ma różnicy między adresem ciągu, a adresem adresu VO.
Nie jestem w 100% zgodny z intencją autora, ale myślę, że on po prostu opisuje, w jaki sposób wymagania wyszukiwania bytu mogą zmienić sposób, w jaki byt i odpowiadające mu VO są strukturami.
Wiele atrybutów nie implikuje wielu zachowań. W rzeczywistości zazwyczaj sugeruje coś przeciwnego. Wiele atrybutów z modułami pobierającymi i ustawiającymi, ale bez zachowania hermetyzującego.
źródło
To zależy od tego, jak chcesz na to spojrzeć.
Innym sposobem jest: „Czy zasada pojedynczej odpowiedzialności narusza podmiot domeny?”
Oba są wytycznymi. Nigdzie w projektowaniu oprogramowania nie ma „zasady”. Istnieją jednak dobre i złe projekty. Obie te koncepcje można wykorzystać na różne sposoby, aby uzyskać dobry projekt.
źródło