Czasami (rzadko) wydaje się, że najlepszym rozwiązaniem jest utworzenie funkcji, która wymaga przyzwoitej liczby parametrów. Jednak kiedy to robię, czuję, że często losowo wybieram porządkowanie parametrów. Zazwyczaj stosuję „porządek ważności”, z najważniejszym parametrem na początku.
Czy jest na to lepszy sposób? Czy istnieje sposób „porządkowania” najlepszych praktyk, który poprawia przejrzystość?
refactoring
clean-code
functions
parameters
order
Casey Patton
źródło
źródło
MessageBox.Show
. Spójrz również na to.Odpowiedzi:
Ogólnie: użyj go .
Napisz test dla swojej funkcji, test w prawdziwym świecie.
Coś , co naprawdę chciałbyś zrobić z tą funkcją .
I zobacz, w jakiej kolejności je odłożyłeś.
Chyba że masz już (lub wiesz) o niektórych funkcjach, które robią coś podobnego.
W takim przypadku: dostosuj się do tego, co już robią, przynajmniej w przypadku pierwszych argumentów.
np. Czy wszystkie przyjmują dokument / obiekt / wskaźnik pliku / serię wartości / współrzędne jako pierwszy argument (y)? Na miłość boską, dostosuj się do tych argumentów .
Unikaj mylenia swoich współpracowników i przyszłego siebie .
źródło
Zwykle stosuję się do tych zasad, choć nie zawsze z takim samym pierwszeństwem. Wydaje mi się, że jest to teraz automatyczny proces myślowy i nie przesadzam z tym, z wyjątkiem projektu publicznego interfejsu API .
Lejek wyboru
1. Najpierw semantyka
Zwłaszcza w OOP wybierz parametry na podstawie ich znaczenia semantycznego dla akcji lub komunikatu. Podpis dobrze nazwanej metody z dobrze nazwanym parametrem powinien:
(Z tych powodów czasami użycie niestandardowych typów lub aliasów zamiast prymitywów może zwiększyć ekspresję podpisu).
2. Następnie znaczenie
Najbardziej „znaczący” parametr jest pierwszy (lub następny ...)
3. Następnie częstotliwość
Częstotliwość ma również znaczenie, szczególnie w języku, w którym nie masz nazwanych parametrów, ale możesz mieć domyślne wartości parametrów pozycyjnych. Oznacza to, że kolejność parametrów nie zmienia się, i oczywiście nie można ustawić parametrów N + 1, jeśli chcesz wymusić domyślną wartość N-tego parametru (z wyjątkiem sytuacji, gdy twój język ma pojęcie parametru zastępczego ).
Dobrą wiadomością jest to, że zwykle częstotliwość jest ważna, więc idzie to w parze z poprzednim punktem. A potem prawdopodobnie od Ciebie zależy, czy stworzysz API, aby miał odpowiednią semantykę.
4. Nie zapominajmy o We / Wy
jeśli twoja metoda / funkcja pobiera dane wejściowe i generuje dane wyjściowe, a te ostatnie nie mają być „zwracane” (za pomocą instrukcji return) ani „wyrzucane” (za pomocą systemu wyjątków), wówczas istnieje możliwość przekazania wartości z powrotem do dzwoniącego przy użyciu innych parametrów (lub parametru wejściowego). Odnosi się to do semantyki iw większości przypadków sensowne jest, aby pierwsze parametry definiowały dane wyjściowe, a ostatnie parametry otrzymywały dane wyjściowe.
Ponadto innym podejściem mającym mniej parametrów i maksymalizację semantyki byłoby zastosowanie podejścia funkcjonalnego lub zdefiniowanie wzorca konstruktora , dzięki czemu można wyraźnie zestawiać dane wejściowe, definiować dane wyjściowe i wyszukiwać je w razie potrzeby.
(Zauważ, że nie wspominam o zmiennych globalnych, ponieważ dlaczego miałbyś użyć jednej, prawda?)
Kilka rzeczy do rozważenia
Użyteczność
Większość z powyższych pokaże się naturalnie, jeśli zastosujesz się do rad ZJR : użyj go!
Zastanów się nad refaktoryzacją
Jeśli martwisz się o porządkowanie parametrów, być może to zmartwienie znajduje swoje źródło w powyższym oraz w tym, że twój interfejs API jest źle zaprojektowany. Jeśli masz zbyt wiele parametrów, coś najprawdopodobniej można skomponować / zmodularyzować i zrefaktoryzować .
Zastanów się nad wydajnością
Należy pamiętać, że implementacje niektórych języków będą miały bardzo istotny wpływ na zarządzanie pamięcią środowiska wykonawczego podczas używania parametrów. Stąd powód, dla którego podręczniki stylu wielu języków zalecają, aby lista parametrów była prosta i krótka . Na przykład przy maks. 4 parametrach. Zostawiam to jako ćwiczenie, aby dowiedzieć się, dlaczego.
Odpowiedź Bevana i wzmianka o zaleceniach Clean Code są również bardzo istotne!
źródło
Z szacunkiem podam, że martwienie się o porządkowanie parametrów martwi się o niewłaściwą rzecz.
W książce wuja Boba „ Czysty kod ” przekonująco opowiada się za tym, aby metody nigdy nie miały więcej niż dwóch argumentów - a większość powinna mieć tylko jeden, jeśli w ogóle. W takim przypadku zamówienie jest oczywiste lub nieważne.
Jednak niedoskonale staram się postępować zgodnie z radą wuja Boba - i to poprawia mój kod.
W rzadkich przypadkach, gdy metoda wydaje się wymagać więcej informacji, dobrym pomysłem jest wprowadzenie obiektu parametru . Zwykle uważam, że jest to pierwszy krok w kierunku odkrycia nowej koncepcji (obiektu) kluczowej dla mojego algorytmu.
źródło
Staram się umieścić parametry IN na pierwszym miejscu, parametry OUT na drugim miejscu. Istnieje również pewne naturalne uporządkowanie, np.
createPoint(double x, double y)
Jest zdecydowanie lepsza niżcreatePoint(double y, double x)
.źródło
addAllTo(target, something1, something2)
. In .Nigdy nie widziałem udokumentowanej „najlepszej praktyki” dotyczącej tego konkretnego tematu, ale moim osobistym standardem jest wymienienie ich w kolejności, w jakiej pojawią się w metodzie, w której są używane, lub jeśli metoda jest bardziej przechodząc do warstwy danych wymienię je w kolejności, w jakiej pojawią się w schemacie db lub metodach warstwy danych.
Ponadto, gdy występuje wiele przeciążeń metody, zauważam, że typowym sposobem jest wylistowanie ich, zaczynając od parametrów wspólnych dla wszystkich (lub większości) metod, przy czym każda inna metoda jest dołączana na końcu dla każdego przeciążenia metody, np. :
źródło
Kolejność: dane wejściowe, dane wyjściowe, parametry opcjonalne.
źródło
Często stosuję się do konwencji C / C ++ polegającej na umieszczaniu
const
parametrów w pierwszej kolejności (tj. Parametrów przekazywanych przez wartość), a następnie tych, które przekazujesz przez odniesienie. To niekoniecznie musi być poprawna metoda wywoływania funkcji, ale jeśli jesteś zainteresowany sposobem, w jaki każdy kompilator obsługuje parametry, spójrz na poniższe linki do reguł rządzących i / lub kolejności, w której parametry są wypychane na stos.http://msdn.microsoft.com/en-us/library/zthk2dkh%28v=vs.80%29.aspx
http://en.wikipedia.org/wiki/Calling_convention
źródło
Zwykle po prostu wybieram kolejność parametrów „co wygląda mniej cyprycznie”. Im mniej razy muszę przejść do definicji metody / funkcji, tym lepiej. I miło jest mieć nazwane parametry opisujące, do czego są używane, w ten sposób, gdy pojawia się mała podpowiedź (VS), to czyni to jeszcze łatwiejszym.
Jeśli masz linie i linie parametrów, możesz rozważyć inny projekt. Cofnij się i zobacz, jak możesz podzielić to na więcej funkcji / metod. To tylko pomysł, ale kiedy mam kilkanaście parametrów w swojej funkcji, prawie zawsze nie jest to problem z parametrami, ale problem z projektem.
źródło
Używanie kilku parametrów jest często wyraźnym wskaźnikiem, że naruszasz SRP w tej metodzie. Metoda, która wymaga wielu parametrów, nie może zrobić tylko jednej rzeczy. Excpetion może być funkcją matematyczną lub metodą konfiguracji, w której rzeczywiście potrzebnych jest kilka parametrów . Unikałbym wielu parametrów, ponieważ diabeł unika wody święconej. Im więcej parametrów używasz w metodzie, tym większa szansa, że metoda jest (zbyt) złożona; tym bardziej złożona oznacza: trudniejsza w utrzymaniu i jest to mniej pożądane.
Zasadniczo wybierasz losowo . Oczywiście możesz pomyśleć, że parametr A jest bardziej odpowiedni niż parametr B ; ale może nie być tak w przypadku użytkowników interfejsu API, którzy uważają B za najbardziej odpowiedni parametr. Więc nawet jeśli byłeś uważny w wyborze kolejności - dla innych może się to wydawać przypadkowe .
Istnieje kilka sposobów wyjścia:
a) Trywialny przypadek: nie używaj więcej niż jednego parametru.
b) Ponieważ nie określiłeś, jaki język wybrałeś, istnieje szansa, że wybrałeś język o nazwanych parametrach . Jest to ładny cukier syntaktyczny, który pozwala rozluźnić znaczenie kolejności parametrów:
fn(name:"John Doe", age:36)
Nie każdy język pozwala na takie subtelności. Co wtedy?
c) Możesz użyć Dictionary / Hashmap / Associative Array jako parametru: np. Javascript pozwala na:
fn({"name":"John Doe", age:36})
co nie jest daleko od (b).d) Oczywiście, jeśli pracujesz ze statycznie typowanym językiem, takim jak Java. możesz użyć Hashmapy , ale stracisz informacje o typie (np. podczas pracy
HashMap<String, Object>
), gdy parametry mają różne typy (i trzeba rzutować).Następnym logicznym krokiem byłoby przekazanie
Object
(jeśli używasz Javy) odpowiednich właściwości lub czegoś bardziej lekkiego jak struct (jeśli napiszesz np. C # lub C / C ++).Praktyczna zasada:
1) Najlepszy przypadek - twoja metoda wcale nie wymaga żadnych parametrów
2) Dobry przypadek - twoja metoda wymaga jednego parametru
3) Dopuszczalny przypadek - twoja metoda wymaga dwóch parametrów
4) Wszystkie pozostałe przypadki powinny zostać ponownie rozpatrzone
źródło
Często złożony obiekt jako parametr jest lepszy - wersja nazwanych parametrów biednego człowieka, która działa na większości platform. I otwiera drzwi do parametrów z zachowaniem do uruchomienia.
Jako przykład większości rzeczy, których nie powinieneś robić, możesz spróbować przeczytać standardową dokumentację biblioteki PHP.
źródło
Zwykle zamawiam je najpierw jako wymagane, a nie według jakiejś połączonej miary ważności i częstotliwości używania zgodnie z „odczuciem” (może być postrzegane jako
ORDER BY required DESC, SOME_MAGIC_FEELING(importancy,frequency)
), a nie zgodnie z żadną konkretną praktyką.Jednak, jak zauważyli inni, myślę, że podstawowym problemem, który sprawia, że jest to problem, jest użycie zbyt wielu parametrów (IMHO, cokolwiek> 3 to zbyt wiele) i to jest prawdziwy problem, którym powinieneś się zająć. Na blogu rebecca murphey znajduje się ciekawy post na ten temat.
Myślę, że gdy masz tylko 1-3 argumenty, prawidłowe uporządkowanie jest dość oczywiste i po prostu „czujesz”, co jest właściwe.
źródło
Podobnie do odpowiedzi @Wyatt Barnetts, cokolwiek więcej niż kilka parametrów lub bardzo wyraźne parametry dla metody, polecam zamiast tego przekazać obiekt. Zazwyczaj jest to łatwiejsze do aktualizacji / konserwacji, bardziej czytelne i eliminuje konieczność martwienia się o zamówienie . Ponadto zbyt wiele parametrów dla metody jest zapachem kodu i istnieją wspólne wzorce refaktoryzacji, które można zastosować, aby pomóc to poprawić.
Jawny przykład:
Ponieważ jest to dość jasno określony przykład, a dodawanie jest przemienne (kolejność nie ma znaczenia), po prostu idź z nim.
Jeśli jednak dodasz coś bardziej złożonego:
Stanie się:
Mam nadzieję że to pomoże...
źródło
Zamów to w dowolny sposób, w jaki według ciebie curry najprawdopodobniej skorzysta. Na przykład najpierw parametry funkcji.
źródło
„Ważne przede wszystkim” nie znaczy wiele. Istnieje kilka konwencji.
Jeśli przekażesz obiekt wywołujący (często nazywany nadawcą), jest to pierwszy.
Na liście powinna być pewna płynność , co oznacza, że powinieneś wiedzieć, o czym jest argument, zanim go przeczytasz. Przykład:
CopyFolder (ścieżka ciągu, rekurencyjny bool);
Jeśli na pierwszym miejscu byłoby rekurencyjne, byłoby to mylące, ponieważ nie ma jeszcze kontekstu. Jeśli już teraz chodzi o kopiowanie (1) folderu (2), wówczas argument rekurencyjny zaczyna mieć sens.
Dzięki temu funkcje podobne do IntelliSense działają dobrze: użytkownik uczy się, wypełniając argumenty, budując zrozumienie metody i jej działania. Podobnie przeciążenia powinny zachować tę samą kolejność dla równych części.
Wtedy nadal możesz znaleźć argumenty, które są „równe” pod tym względem i możesz ulec pokusie, aby kolejność zależała od rodzaju argumentu. Tylko dlatego, że kilka strun pod rząd, a potem kilka boolean wygląda ładniej. Na pewnym poziomie stanie się to raczej sztuką niż umiejętnością.
Nie dbam zbytnio o stwierdzenie, że powinieneś zawinąć wszystkie argumenty w obiekt, aby otrzymać jeden argument. To tylko oszukanie samego siebie (nie sprawia, że metoda jest mniej skomplikowana, nadal ma wszystkie te argumenty, po prostu je ukryłeś). Może to nadal być wygodne, jeśli prześlesz zestaw od metody do metody kilka razy, refaktoryzacja stanie się znacznie łatwiejsza, ale pod względem projektowym udajesz, że robisz różnicę. To nie tak, że skończysz z sensownym obiektem, który coś reprezentuje, będzie to tylko garść argumentów, niczym nie różniących się od listy w deklaracji metody. Nie sprawi, że wujek Bob będzie szczęśliwy.
źródło