2012-02-24 12 views
5

Czytam książkę Erica Evansa o DDD i mam pytanie do następującego cytatu. W jaki sposób można wykonać metodę equals(), gdy nie powinieneś używać atrybutów? Używam JPA i mam atrybut id, który jest unikalny, ale nie jest to ustawione, dopóki nie utrzymasz encji. Więc co robisz? Zaimplementowałem metodę równości opartą na atrybutach i rozumiem, dlaczego nie powinieneś, ponieważ nie powiodło się w moim projekcie.Elementy w projekcie opartym na domenie

Sekcja o podmiotach:

Gdy obiekt wyróżnia się swojej tożsamości, a nie jego cechy sprawiają, że tę podstawową jego definicją zawartą w modelu. Zachowaj definicję klasy prostą i skoncentrowaną na ciągłości cyklu życia i tożsamości . Zdefiniuj sposób odróżnienia każdego obiektu niezależnie od jego postaci lub historii. Bądź świadomy wymagań, które wymagają dopasowywania obiektów według atrybutów. Zdefiniuj operację, która jest gwarantowana dla , tworząc unikalny wynik dla każdego obiektu, prawdopodobnie poprzez dołączenie symbolu gwarantowanego unikatowo. Ten sposób identyfikacji może pochodzić z zewnątrz lub może być arbitralnym identyfikatorem utworzonym przez i dla systemu, ale musi odpowiadać rozróżnieniu w modelu. Model musi definiować, co to znaczy być tym samym.

http://www.amazon.com/Domain-Driven-Design-Tackling-Complexity-Software/dp/0321125215

+0

Możliwy duplikat, zobacz http://stackoverflow.com/questions/5031614/the-jpa-hashcode-equals-dilemma – MRalwasser

+0

id działa dobrze dla mnie: http://stackoverflow.com/questions/7579404/using-auto-generated-id-of-hibenate-entity-object-in-the-equals-and-hashcode-met – NimChimpsky

Odpowiedz

1

para zbliża się możliwe:

  • Użyj klucza biznesowego. Jest to najbardziej "zgodne z DDD" podejście. Przyjrzyj się dokładnie wymaganiom domeny i biznesu. W jaki sposób Twoja firma identyfikuje na przykład Klientów? Czy używają numeru ubezpieczenia społecznego lub numeru telefonu? W jaki sposób Twoja firma rozwiązałaby ten problem, gdyby był oparty na papierze (bez komputerów)? Jeśli nie ma naturalnego klucza biznesowego, utwórz surogat. Wybierz klucz biznesowy, który jest ostateczny i użyj go w equals(). W książce DDD znajduje się sekcja poświęcona temu konkretnemu problemowi.

  • W przypadkach, gdy nie istnieje żaden naturalny klucz biznesowy, można wygenerować identyfikator UUID. Miałoby to również zaletę w systemie rozproszonym, w którym to przypadku nie trzeba polegać na scentralizowanym (i potencjalnie niedostępnym) zasobniku, takim jak baza danych, w celu wygenerowania nowego identyfikatora.

  • Istnieje również opcja polegania na wartości domyślnej equals() dla klas jednostek.Porównałoby to dwie lokalizacje w pamięci iw większości przypadków wystarcza, ponieważ Unit Of Work (sesja hibernacji) utrzymuje wszystkie jednostki (ten wzorzec ORM nazywa się Identity Map). To nie jest wiarygodne, ponieważ będzie przerwa jeśli używasz podmioty, które nie są ograniczone do zakresu jednego hibernacji sesji (wątki sądzę, oderwane podmioty itp)

Co ciekawe, „urzędowy” próbka DDD używa bardzo lekki ramy gdzie każda klasa jednostka pochodzi z Entity interfejs z jednej metody:

boolean sameIdentityAs(T other) 
// Entities compare by identity, not by attributes. 
+0

Powiedzmy, że podmiot był Pytanie. Co bym użył? Do tej pory opierałem się na wygenerowanym identyfikatorze. – LuckyLuke

+0

Zależy od Twojej domeny, może tekst samego pytania (w tym przypadku może to Wartość nie Podmiot), ale bardziej prawdopodobnie coś w rodzaju numeru pytania. Naprawdę zależy od Twojej domeny. – Dmitry

1

Jeśli obiekt nie jest jeszcze trwała, a następnie jest jakaś złego w porównywaniu 2 obiektów na podstawie ich atrybutów?

Nie jestem pewien, dlaczego to się nie powiodło w twoim projekcie, ale z mojego doświadczenia wynika, że ​​porównanie oparte na atrybutach prawie zawsze jest śliskie, jeśli twoje atrybuty nie są ostateczne. Oznacza to, że 2 obiekty, które są teraz równe, mogą nie być równe po jakimś czasie. To jest bardzo złe.

Biorąc pod uwagę, że większość klas Java jest pisana wraz z ich akcesoriami, porównywanie atrybutów uważa się za zły pomysł.

Najprawdopodobniej najpierw sprawdziłbym, czy pole ID nie jest puste. Jeśli jest zerowy, powrócę do porównania atrybutów. Jeśli nie ma wartości NULL, po prostu użyj go i nie rób nic innego. Czy to ma sens?

+2

To niebezpieczna rzecz. Jeśli przechowujesz obiekt w HashSet przed przypisaniem jego identyfikatora, HashSet zostanie uszkodzony. –

+0

Na pewno. Ale zakładam, że utrzymasz obiekt, aby uzyskać identyfikator. W takim przypadku generalnie wolę otrzymywać utrwalony obiekt, który jest zwracany i używać go. Zasadniczo nie modyfikuj stanu obiektu, który jest używany w sprawdzaniu równości. – Pavan

+0

Porównując obiekty na podstawie ich atrybutów, zachowuje się jak obiekt wartości, a nie encja. Obiekty wartości i encje mają zupełnie inną semantykę w DDD, więc nie powinieneś opierać równości Entity na atrybutach. –

1

Biorąc Person klasy z atrybutami name, surname. Kiedy osoba w wieku 21 lat zmienia swoją nazwę to wciąż ta sama osoba (równa się true)? Jeśli piszesz na podstawie atrybutów, to nie byłaby to ta sama osoba, więc moim zdaniem najlepszym podejściem jest testowanie równości jednostek na ich identyfikatorze biznesowym (unikalnym i niezmiennym w całym cyklu życia jednostki).

0

Innym rozwiązaniem może być użycie pola UUID w twojej encji.

W tym przypadku można użyć UUID jako klucza podstawowego lub tylko dla równych.

@Entity 
public class YourEntity{ 

    @Id 
    private String uuid = UUID.randomUUID().toString(); 

    // getter only... 

} 
Powiązane problemy