Załóżmy interfejs zawierający te metody:
Car find(long id);
List<Car> find(String model);
Czy lepiej zmienić ich nazwy w ten sposób?
Car findById(long id);
List findByModel(String model);
Rzeczywiście, każdy programista, który korzysta z tego interfejsu API, nie musi patrzeć na interfejs, aby poznać możliwe argumenty find()
metod początkowych .
Więc moje pytanie jest bardziej ogólne: Jaka jest korzyść z używania przeciążonych metod w kodzie, ponieważ zmniejszają one czytelność?
Odpowiedzi:
Jest to stosunkowo niewielki problem w porównaniu z wieloma innymi praktykami złej czytelności, na które możesz być podatny, więc powiedziałbym, że to głównie kwestia gustu, jak nazywasz swoje metody.
Powiedziawszy to, jeśli zamierzasz coś z tym zrobić, postąpiłbym zgodnie z następującą praktyką:
Przeciążenie, jeśli ...
Metody są zgodne z prawie tą samą umową, ale działają po prostu na różnych danych wejściowych (wyobraź sobie operatora telefonicznego, który może sprawdzić twoje konto na podstawie twojego osobistego numeru identyfikacji podatkowej, numeru konta lub imienia i daty urodzin). Obejmuje to zwracanie tego samego typu danych wyjściowych .
Użyj innej nazwy, jeśli ...
Metody robią zasadniczo różne rzeczy lub zwracają różne dane wyjściowe (jak Twoja sprawa). Możesz rozważyć użycie innej nazwy, jeśli ktoś uzyskuje dostęp do bazy danych, a drugi nie.
Ponadto, jeśli zwracany typ jest inny, zmieniłbym również czasownik, aby wskazać, że:
źródło
W każdym przypadku zaleciłbym użycie innej nazwy. Możliwe, że w przyszłości będziesz chciał dodać inną metodę, powiedzmy
List<Car> findByMake(String make)
, w przeciwieństwie doList<Car> findByModel(String model)
. Nagle nazywanie wszystkiegofind
przestaje mieć sens. Twoje metody są również mniej prawdopodobne, że zostaną przypadkowo użyte nieprawidłowo, jeśli ich nazwy podają więcej informacji o tym, jak należy je stosować.źródło
find(Make val)
ifind(Model val)
. Wówczas metody wygody, takie jak,findByMake(String val)
byłyby o wiele bardziej jasne, co faktycznie robią. W końcu aString
nie jest ani marką, ani modelem, więc metoda powinna wyjaśnić, co tak naprawdę robi.Jeśli zmienisz nazwę metody, nie będzie ona już przeciążona. Samo przeciążenie niekoniecznie powoduje, że kod jest mniej czytelny, jednak może utrudnić wykonanie implementacji, jeśli składnia nie jest jasna.
Wiele języków używa przeciążania metod jako sposobu prezentacji interfejsu dla funkcjonalności, w której parametry mogą być opcjonalne i sugerowane są domyślne parametry opcjonalne. Jest to szczególnie prawdziwe w przypadku języków, które nie obsługują domyślnej składni parametrów w deklaracji metody.
Robiąc to:
ratuje cię przed zrobieniem tego:
Co jest bardziej czytelne, to naprawdę sprowadza się do ciebie. Osobiście wolę drugą opcję, szczególnie gdy lista parametrów staje się trochę długa, ale przypuszczam, że to nie ma znaczenia, o ile jesteś konsekwentny w całym interfejsie API.
Trudność z przeciążeniem pojawia się, gdy chcesz, aby funkcje, które wykonują zasadniczo to samo, i gdzie chcesz, aby listy parametrów były takie same, ale typy zwracane były różne. Większość języków nie wie, jak rozróżnić dwie metody o tej samej nazwie, ale z różnymi typami zwrotów. W tym momencie musisz pomyśleć o użyciu ogólnych, zmianie interfejsu parametrów lub zmianie nazwy jednej z metod, aby wskazać różnicę w typie zwrotu. Tutaj czytelność może stać się dużym problemem, jeśli nie zdecydujesz się na prosty i przejrzysty schemat nazewnictwa, aby poradzić sobie z takimi sytuacjami.
Nazywanie przeciążonych metod
GetSomething()
iGetSomethingEx()
nie będzie dużo mówić o różnicach między metodami, szczególnie jeśli to typy zwracane są jedynymi różnicami między nimi. Z drugiej strony,GetSomethingAsInt()
iGetSomethingAsString()
powiem ci trochę więcej o tym, co robią metody, i chociaż nie jest to przeciążenie, wskazuj, że obie metody robią podobne rzeczy, ale zwracają różne typy wartości. Wiem, że istnieją inne sposoby nazywania metod, jednak w celu zilustrowania tego, te prymitywne przykłady powinny zrobić.W przykładzie OP zmiana nazwy nie jest absolutnie niezbędna, ponieważ parametry metody są różne, ale to sprawia, że określenie nazwy metody jest nieco bardziej precyzyjne. Ostatecznie sprowadza się to do rodzaju interfejsu, który chcesz przedstawić użytkownikom. Decyzja, czy nie przeciążać, nie powinna być podejmowana wyłącznie na podstawie własnego postrzegania czytelności. Przeciążenie metod może na przykład uprościć interfejs API i zmniejszyć liczbę metod, które deweloper może potrzebować pamiętać, z drugiej strony może zaciemnić interfejs w stopniu, który następnie wymaga od programisty przeczytania dokumentacji metody, aby zrozumieć, która forma metody do użycia, podczas gdy posiadanie wielu podobnie, ale opisowo nazwanych metod może sprawić, że bardziej oczywiste będzie po prostu czytanie nazwy metody co do jej celu.
źródło
Preferuj przeciążanie, dopóki metody zwracają to samo i postępują zgodnie z tą samą umową. Przeładowanie uwalnia kod wywołujący od niepotrzebnego zatwierdzania typu parametru.
Załóżmy, że funkcja wywołująca odbiera zapytanie jako parametr i wykonuje inne przetwarzanie przed i / lub po wywołaniu
find
.Jeśli chcesz zmienić typ tego zapytania z dowolnego powodu (np. Z prostego ciągu identyfikatora na w pełni funkcjonalny obiekt zapytania jakiegoś rodzaju), możesz wprowadzić tę zmianę w funkcji wywołującej po prostu zmieniając podpis funkcji aby zaakceptować nowy typ parametru bez obawy o zmianę metody wywoływanej w klasie.
Jeśli wdrożysz
findById
ifindByQueryObject
osobno, będziesz musiał wyśledzić każde połączenie, aby wprowadzić tę zmianę. W przykładzie zmieniłem tylko jedno słowo i skończyłem.źródło
findByFoo
aby wcześniej wykryć niezgodności typów.