Czy lista parametrów metody powinna zawierać obiekty czy identyfikatory obiektów?

10

Nasze zespoły prowadzą następującą dyskusję:

Powiedzmy, że mamy dwie następujące metody:

public Response Withdraw(int clubId, int terminalId,int cardId, string invoice, decimal amount);

public Response Withdraw(Club club, Terminal terminal,Card card, string invoice, decimal amount);

to, co jest przesyłane przez sieć, to tylko identyfikatory.

jedna strona mówi, że pierwsza metoda jest poprawna, ponieważ mamy tylko identyfikatory terminala i klubu i powinno być jasne, że nie mamy nic innego, takie jest moje podejście.

druga strona twierdzi, że druga metoda jest poprawna, ponieważ jest bardziej elastyczna.

Znamy ideę parametru obiektu, druga strona uważa również, że parametr obiektu powinien mieć obiekty jako właściwości.

Jakie jest właściwe podejście?

Może istnieje trzecie, jeszcze lepsze podejście?

Mithir
źródło
Co? ...........
James
1
Kontekst? Serwis internetowy? WCF?
CodesInChaos
1
@James - przepraszam, że napisałem to pytanie dość szybko, czy możesz mi powiedzieć, czego nie rozumiem, abym mógł go edytować?
Mithir
@CodesInChaos, metody są w rzeczywistości metodami BL
Mithir

Odpowiedzi:

10

Odpowiedź zależy od kontekstu.

Jeśli klient ma mieć wszystkie te obiekty już dostępne , użyłbym parametrów obiektu. W przeciwnym razie ich kod będzie wyglądał na bardziej skomplikowany niż powinien. (Np. Będą mieli club.getId()np. Połączenia ).

Jeśli klient będzie miał łatwy dostęp do identyfikatorów , być może drugie podejście jest lepsze, ponieważ nie chcesz, aby klient musiał składać / ładować wszystkie te obiekty, jeśli naprawdę potrzebujesz tylko identyfikatorów.

Opcją jest podanie obu metod , aby klient mógł wybrać, która z nich ma zostać użyta (pod warunkiem, że nie zaśmieca to interfejsu API)

Zasadniczo parametry obiektu są bardziej rozszerzalne, ponieważ jeśli w przyszłości potrzebujesz innej części danych do wykonania pracy, nie musisz wprowadzać innej metody, która pobiera te dodatkowe informacje.

Wreszcie, sygnatury metod nie powinny być podyktowane specyfiką tego, co robi metoda (w twoim przypadku, co dokładnie przechodzi przez drut). Interfejs API powinien abstrakcyjnie mieć sens, więc jeśli zmiany w implementacji nie zostaną wkręcone.

c_maker
źródło
3
+1 Dodałbym tylko jeszcze jeden punkt: w przypadku metod nazywanych zdalnie („za drutem”?) Przekazywanie obiektów może wiązać się z głęboką serializacją dużego drzewa obiektów. Identyfikatory są doskonałym zamiennikiem dla obiektów, gdy martwisz się wielkością ładunku zdalnego połączenia.
Ross Patterson
1
W tym przypadku wygląda na to, że jesteś połączony z zestawem abstrakcji, więc przekazanie Id nie da ci większej elastyczności i prawdopodobnie zwiększy prawdopodobieństwo odwrócenia parametrów. Pytanie brzmi, jak ściśle kod w metodzie jest połączony z abstrakcjami, które przekazuję? Na przykład metoda taka jak „validateCreditCard (karta ciąg, ciąg cvi)” prawdopodobnie powinna pozostać przy prymitywach, aby uniknąć ścisłego powiązania z jakimś rodzajem obiektu CreditCard.
ipaul
Spotkam się w środku i użyję interfejsu z listy parametrów. Wtedy twój klub może być klubem, ale także sauną w przyszłości.
Pieter B
13

Pierwsze podejście wskazuje na pierwotną obsesję . Ponieważ przekazujesz liczby int i ciągi znaków, programiście bardzo łatwo popełni błąd (np. Przekazując wartość clubId do parametru terminalId). Spowoduje to trudne do znalezienia błędy.

W drugim przykładzie nie można przejść do klubu, gdy oczekuje się terminala - dałoby to błąd czasu kompilacji.

Mimo to nadal bym na to patrzył string invoice. Czy faktura jest naprawdę ciągiem? Co amountznaczy Jest to bardziej prawdopodobna wartość pieniężna.

Wspomniałeś w swoim pytaniu, że „przesyłane przez sieć to tylko identyfikatory”. Jest to poprawne, ale nie pozwól, aby to wymaganie zamazało Twoją domenę.

Najlepszym wytłumaczeniem, jakie widziałem na korzyść tego podejścia, była reguła 3 obiektu Calisthenics :

Int jako taki jest po prostu skalarem, więc nie ma znaczenia. Gdy metoda przyjmuje int jako parametr, nazwa metody musi wykonać całą pracę polegającą na wyrażeniu intencji. Jeśli ta sama metoda zajmuje godzinę jako parametr, o wiele łatwiej jest zobaczyć, co się dzieje. Takie małe obiekty mogą sprawić, że programy będą łatwiejsze w utrzymaniu, ponieważ nie można przekazać roku do metody, która wymaga parametru Hour. W przypadku pierwotnej zmiennej kompilator nie może pomóc w pisaniu poprawnych semantycznie programów. Za pomocą obiektu, nawet małego, dajesz zarówno kompilatorowi, jak i programistom dodatkowe informacje o tym, czym jest wartość i dlaczego jest używana.

MattDavey
źródło
Więc preferowane jest drugie podejście? nawet jeśli istnieje obiekt klubowy z wypełnioną tylko właściwością id?
Mithir,
Wygląda to na przypadkowy blog. Nie ma dowodów na to, co jest preferowane. Kogo naprawdę obchodzi, co jest preferowane? Zrób to, co Ci odpowiada
James
@James Nie ma ostatecznej odpowiedzi na to pytanie, zwłaszcza, że ​​PO nie dał nam zbyt dużego kontekstu. Każdy, kto kategorycznie twierdzi, że jedno podejście jest lepsze od drugiego, czyni OP nieprzyjemnością. To nie jest tak czarno-białe.
MattDavey
1
@James Właśnie wskazałem, że pierwsze podejście bardzo ułatwia wprowadzenie trudnych do znalezienia błędów. Nie twierdzę, że typy pierwotne są złe, ale celem typów pierwotnych jest budowanie znaczących typów domen. Używanie ich poza tym kontekstem jest samą definicją pierwotnego zapachu kodu obsesji.
MattDavey,
5
@James: To, co powiedział MattDavey, jest ustalonym faktem. Nie mówi, że rodzime typy są złe, co on mówi, że to: someMethod (int, int, int, string, decimal) jest dużo trudniejszy do zrozumienia i użycia przez klienta niż someMethod (Club, Terminal, Card, String , dziesiętny)
c_maker
2

Nie ma właściwej odpowiedzi na to pytanie. Każda z opcji może być odpowiednia do pracy. Cóż, prawie w każdym razie, argument faktury podniósł bruzdę na moim czole, nie mam pojęcia, co to jest po przeczytaniu kodu.

Jeśli wyślesz identyfikator, oba systemy muszą być ściśle powiązane z tym, co reprezentuje. ClubID jest kluczem w tabeli klubów. Co więcej, zarówno osoba wywołująca, jak i osoba odbierająca muszą uzgodnić, jak nazywa się tabela Clubs i w której bazie danych się znajduje. Jeśli nie chcesz lub nie możesz narzucić tego ograniczenia, możesz przekazać obiekt przy użyciu wspólnego opisu, natywny, serializowany, xml, name = wartość cokolwiek, plik ini :)

To, jak zidentyfikowałeś, będzie cię kosztować „za drut”. Uniknięcie tego, wysyłając identyfikator kosztuje cię gdzie indziej. Więc który z nich najbardziej Cię boli, teraz (lub może być później ...) jest wskaźnikiem dobra kontra zła.

Tony Hopkinson
źródło