Identyfikator vs obiekt domeny jako parametr metody


10

Czy istnieją obiektywne argumenty przemawiające za lub przeciw używaniu obiektów vs unikalny identyfikator jako parametry metody / funkcji? (i członkowie innych przedmiotów?). Specjalnie w kontekście języków o typie statycznym (C # / Java / Scala)

Plusy samego obiektu:

  • Więcej bezpiecznych połączeń. W przypadku identyfikatorów istnieje ryzyko niewłaściwego uporządkowania argumentów. Można to jednak złagodzić, utrzymując klasę „mini” dla każdej klasy, która przechowuje tylko identyfikator tej klasy.
  • Zdobądź raz z wytrwałości, nie musisz więcej
  • Z identyfikatorem, jeśli typ identyfikatora zmienia się, powiedzmy int -> long, wówczas wymagałoby to zmiany z możliwością wystąpienia błędów .. (courtsey: https://softwareengineering.stackexchange.com/a/284734/145808 )

Plusy używania identyfikatora:

  • Przez większość czasu nie potrzeba rzeczywistego obiektu, wystarczyłoby tylko uniqueid, więc posiadanie identyfikatora oszczędza czas od uzyskania go z trwałości.

Mieszanka tych technik, o ile widzę, miałaby tylko wady obu i zalety obu.

Biorąc pod uwagę, że jest to konkretnie określony problem, mam nadzieję, że istnieją obiektywne odpowiedzi, a nie typy „myślę” lub „lubię”… :-).

EDYCJA: Kontekst sugestii komentatora - Jedynym ograniczeniem są języki o typie statycznym. Ta aplikacja jest aplikacją ogólnego przeznaczenia, chociaż chętnie otrzymuje odpowiedzi na podstawie konkretnych scenariuszy użytkowania.

EDYCJA: Więcej kontekstu. Powiedz, że mam system zarządzania książkami. Mój model to:

Book: { id: Int, isbn: String, donatedBy: Member, borrowedBy: Member }
Member: {id: Int, name: String}

Table- wishlist: { isbn: String, memberId: Int}
Table- borrows:  { id: Int, memberId: Int}  

Method: 
isInWishList( book: Book, member: Member ) vs isInWishList( bookId: Int,  memberId: Int)

handleBorrowRequest( memberId: Int, book: Book ){ 
   //the login system doesn't actually get the entire member structure, only the member id. I don't need the full member yet. can run a query to verify that the memberId has less than max allowed books for borrowing. 
}

Dlaczego miałbym chcieć zachować tylko identyfikator, a nie pełnego członka? Powiedz, kiedy otrzymuję informacje o książce, rzadko muszę wiedzieć, kto ją podarował lub pożyczył. Uzyskanie pełnych informacji w celu wypełnienia pól darowanych i pożyczonych to przesada.

Oczywiście, to tylko moje punkty. Jestem pewien, że brakuje mi rzeczy, więc chciałem wiedzieć, jakie są punkty za / przeciw.


Czy możesz edytować swoje pytanie w nieco większym kontekście? Nie jest jasne, jaki jest inny scenariusz. Idę do odgadnięcia , że mówimy o obiektach, które są zarządzane przez system ORM (jak Hibernate) i że przez „mini-klasy” masz na myśli leniwy ładowaną proxy obiektu.
— Darien


Dodanie tutaj jako komentarza (dopóki nie zdobędę wystarczającej ilości kontekstu, aby rozwinąć się do pełnej odpowiedzi): O ile nie kodujesz wartości identyfikatora w swoim kodzie (duża nie-nie), nadal będziesz musiał załadować wartości identyfikatora skądś, prawda? „
— Przez

@hjk Dodano więcej kontekstu, dzięki. Masz rację - nadal musisz gdzieś ładować wartości ID. Nie chodzi jednak o to, by nie „dotykać” DB, ale o minimalizowanie użycia i przepustowości do DB. Mogę dostać identyfikatory wszystkich, którzy chcą pożyczyć książkę, ale w rzeczywistości uzyskanie ich pełnych danych byłoby niepotrzebne.
— 0nt

Wydaje się, że zależałoby to od kilku rzeczy: (1) czy przypadki użycia wymagają rzeczywistych atrybutów (kolumn) czy tylko identyfikatora, który zależy od samych przypadków użycia; (2) czy używasz pewnych technik buforowania lub zwiększających wydajność, które sprawiłyby, że zapytanie ID-atrybuty byłoby łatwe, i czy twoje przypadki użycia byłyby na tyle ciężkie, aby przerwać takie schematy buforowania.
— rwong

Odpowiedzi:


8

W zależności od środowiska i kontekstu problemu, potrzeba przejścia do bazy danych może zostać złagodzona, w wyniku czego (IMO) argument za używaniem tylko identyfikatora zostaje utracony.

Na przykład PHP Doctrine2 ORM, EntityManager::getReferencektóry tworzy leniwie załadowane proxy do encji przy użyciu podanego identyfikatora; Nie wiem, ilu innych ORM to robi, ale w przybliżeniu pasuje to do pojęcia „mini-klasy”, o której wspominasz. Dla większości celów i celów jest to w pełni uwodniona istota, więc możesz ją przekazywać i używać jak jakikolwiek inny.

Jedyny przypadek, w którym tak się nie dzieje, to podanie niepoprawnego identyfikatora, w którym to przypadku i tak chcesz przejść do bazy danych, aby sprawdzić; ponadto, aby obniżyć koszty uzyskania encji, większość ORM ma funkcję buforowania (pierwszego i drugiego poziomu) w jakiejś formie.

Gdy zmniejszymy potrzebę i koszt przejścia do bazy danych, w dużej mierze jesteśmy za tym, aby użyć encji jako parametru:

  1. Wpisz bezpieczeństwo.
  2. Dzwoniąca wymaga mniej wiedzy. Deweloper po 6 miesiącach nie może omyłkowo podać identyfikatora niewłaściwej jednostki.
  3. Niższe koszty refaktoryzacji. Jeśli metoda miałaby się zmienić tak, aby wymagała 2 informacji od jednostki, zmiana dzwoniącego w celu jej dostarczenia nie wiąże się z żadnymi kosztami, zakładając, że osoba dzwoniąca otrzymała w pełni uwodniony byt.
  4. Wymagana mniejsza walidacja dla każdej metody. Wiele metod może zakładać, że podana jednostka istnieje w bazie danych (ponieważ pochodzi z ORM), a zatem nie musi już sprawdzać poprawności identyfikatora.
  5. (Potencjalnie) mniej wywołań bazy danych. Jeśli przekazujesz identyfikator do 3 metod, a każda z nich musi je zweryfikować lub pobrać więcej danych o encji, to 3 razy więcej wywołań bazy danych niż 1 metoda pobierania encji i 2 operujące na niej.

Oczywiście zdarzają się przypadki, w których można chcieć przekazać tylko identyfikator: na przykład podczas przekraczania ograniczonej granicy kontekstu (w projektowaniu sterowanym domeną). Jeśli weźmiemy pod uwagę dwa ograniczone konteksty z różnymi wyobrażeniami o tym, co składa się na konto (np. Finanse vs. relacje z klientami), nie możemy przekazać konta kontekstu A do kontekstu B. Zamiast tego identyfikator konta (w języku domeny) może być przekazywanym.


Buforowanie nie skalowałoby się dobrze przy wielu wystąpieniach aplikacji. Mam swoje własne buforowanie. Punkty są jednak doskonałe.
— 0nt

Myślę, że jeszcze jeden argument przeciwko identyfikatorom polega na tym, że używanie identyfikatora oznacza wywoływanie trwałości oprócz sprawdzania poprawności, aby faktycznie uzyskać obiekt.
— 0nt

3

W przypadku tego rodzaju pytań deleguję do dowolnego rozwiązania, które najlepiej komunikuje moją intencję programisty i sprawia, że ​​praca w „Future Greg” jest najłatwiejsza.

Używanie obiektu jako argumentu ułatwia prawidłowe wywołanie metody za 6 miesięcy i zapomniałem o drobnych szczegółach tej aplikacji. Opierając się na „jest to książka na przykładzie listy życzeń tej osoby”, powiedzmy, że isInWishListmetoda naprawdę wymaga jedynie porównania liczb całkowitych książek i członków. W rzeczywistości ta jedna metoda wymaga tylko dwóch fragmentów danych, aby wykonać swoje zadanie. Cofnijmy się teraz od tej jednej metody i spójrzmy na cały system oprogramowania. Wątpię, aby do działania potrzebował tylko identyfikatora książki i identyfikatora członka. W każdym razie będziesz wyciągać pełną książkę i członka z bazy danych, zanim nawet zadzwonisz, isInWishListponieważ prawdopodobnie będziesz musiał zrobić coś więcej niż tylko wywołać tę jedną metodę. Może i tak, ale w większości przypadków musisz zrobić więcej.

Biorąc to pod uwagę, realistycznie nie poniesiesz kary za wydajność, pobierając i mapując oba obiekty w całości z bazy danych. Teoretycznie będziesz potrzebować mniej wywołań bazy danych, ale w praktyce przekonasz się, że to po prostu nieprawda. Jeśli przekażesz te identyfikatory jako parametry w ciągu zapytania z powrotem na serwer, to tak, wystarczy pobrać listę życzeń z bazy danych. Jest to jednak bardzo wąski widok całej aplikacji. Będą scenariusze, gdy wykonujesz inne operacje oprócz sprawdzania listy życzeń --- na przykład dodając książkę do listy życzeń. Nie chcesz dodawać duplikatów.

Wybierz rozwiązanie, które jest najłatwiejsze dla nowego programisty lub Twojego Future Self do zrozumienia, a mianowicie przekazywanie obiektów Booki Member. Dopiero po znalezieniu rzeczywistego problemu z wydajnością powinieneś naprawdę zająć się samym przekazywaniem ID.

Możemy też pamiętać, że statycznie pisane języki, takie jak Java, oferują przeciążanie metod, więc możesz mieć swoje ciasto i je zjeść:

public boolean isInWishList(int bookId, int memberId) {
    // ...
}

public boolean isInWishList(Book book, Member member) {
    return isInWishList(book.getId(), member.getId());
}

Prawdziwą odpowiedzią na to pytanie jest napisanie obu metod, wywołanie wersji z liczbą całkowitą z mocno wpisanej wersji, a Bob jest twoim wujem.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.