Czy dobrze znany identyfikator biznesowy podmiotu powinien być reprezentowany przez dedykowany typ w DDD / OOP?

9

W praktyce oznacza to użycie niestandardowego (niezmiennego) w classstosunku do stringjakiegoś innego rodzaju prymitywnego.

Przykłady:

  1. Publikowanie: międzynarodowy standardowy numer książki.
  2. Finanse: międzynarodowy numer identyfikacyjny papierów wartościowych.

Zalety:

  1. Może zapewnić format identyfikatora.
  2. Zostaje pierwszorzędnym członkiem modelu.

Niedogodności:

  1. Dodaje tarcie związane z trwałością (np. Entity Framework).
  2. Więcej kodów.
Legowisko
źródło
Czy powinieneś użyć niestandardowej klasy? Pewnie. Czy powinieneś używać ich jako identyfikatorów? Absolutnie nie :) Identyfikator o znaczeniu biznesowym spowodowałby kłopoty po drodze.
Songo,
2
@Songo Dla mnie jest to argument, że identyfikatory powinny mieć semantykę wartości , ale typy pierwotne nie są jedynymi typami z semantyką wartości, więc niekoniecznie wyklucza to klasę imo. Nie krępuj się jednak opublikować konkurencyjną odpowiedź, ponieważ zapomniałem o tym powiedzieć.
Ixrec
1
Moje stare pytanie dotyczyło tego tematu różnymi opiniami: programmers.stackexchange.com/questions/281827/ ... Poszedłem z tworzeniem typów i nadal to robię.
Ziv

Odpowiedzi:

6

Jeśli możesz dać klasie wystarczająco przydatną funkcję, aby uzasadnić dodatkową złożoność braku bycia ciągiem, zrób to. Podejrzewam, że w przypadku identyfikatorów takich jak ISBN i ISIN tak nie jest.

Aby klasa identyfikatora była przydatna, oczekiwałbym, że będzie wyglądać mniej więcej tak:

class ISIN {
    fromCUSIP()
    fromRawISINString()
    toString(ISIN::FormatType)
    getExchange()
    getCountryCode()
    getLastFourDigits()
    getWhateverCode()
    ...
}

Jeśli zamiast tego wygląda to bardziej tak:

class ISIN {
    getString()
    setString()
}

Potem porzuciłbym klasę całkowicie, wszędzie używałem regularnych ciągów i upewniłem się, że konsekwentnie używam „isin” we wszystkich odpowiednich nazwach zmiennych.

Zauważ, że w niektórych językach dodanie nowego typu prawie nie ma „dodatkowej złożoności” w typowych programach, w którym to przypadku zachęcamy do utworzenia nowego typu, nawet jeśli w ogóle nie miałby żadnej funkcjonalności. Ale nie jest tak w przypadku większości tradycyjnych języków OOP, takich jak C ++.

Ixrec
źródło
6

Powiedziałbym: idź po to. Twierdziłbym, że zalety przewyższają wady w tym przypadku. Dodatkowy kod prawdopodobnie będzie dość minimalny, a problem trwałości można łatwo rozwiązać, zapewniając jakiś konwerter między nową klasą a typem, którego oczekuje baza danych (nigdy nie korzystałem z Entity Framework, ale wiem, że jest to stosunkowo bezbolesne w Hibernować).

Jedną z zalet, które można uzyskać, definiując własną klasę, jest to, że kompilator może zagwarantować, że wszelkie metody, które chcą uzyskać numer ISBN lub numer ISIN, będą wiedziały w czasie kompilacji, jeśli spróbujesz przekazać złą wartość. Znacznie trudniej będzie również przypadkowo zastąpić to pole w Twojej jednostce. Możemy całkowicie uniknąć typowych błędów:

book.setAuthor(otherBook.getAuthorName());
book.setIsbn(otherBook.getAuthorName());
book.setPrice(otherBook.getPrice())

Jeśli ISBN jest klasą, a nie prymitywnym typem, powyższy kod nawet się nie skompiluje, oszczędzając później dużo czasu na debugowanie.

Matt Watson
źródło
1
setery i gettery? Czy to 1992?
Miles Rout