Rozważ funkcję bez parametrów ( edytuj: niekoniecznie), która wykonuje pojedynczy wiersz kodu i jest wywoływana tylko raz w programie (choć nie jest niemożliwe, że będzie ona potrzebna ponownie w przyszłości).
Może wykonać zapytanie, sprawdzić niektóre wartości, zrobić coś z wyrażeniem regularnym ... wszystko niejasne lub „hacky”.
Uzasadnieniem tego byłoby uniknięcie trudnych do odczytania ocen:
if (getCondition()) {
// do stuff
}
gdzie getCondition()
jest funkcja jednowierszowa.
Moje pytanie brzmi: czy to dobra praktyka? Wydaje mi się to w porządku, ale nie wiem o długim okresie ...
getCondition
? Jeśli jest tak mały i rzadko używany, jak mówisz, to nadanie mu nazwy niczego nie osiąga.Odpowiedzi:
Zależy od tej jednej linii. Jeśli wiersz jest czytelny i zwięzły sam w sobie, funkcja może nie być potrzebna. Prosty przykład:
OTOH, jeśli funkcja nadaje dobre imię linii kodu zawierającej np. Złożone, trudne do odczytania wyrażenie, jest to dla mnie całkowicie uzasadnione. Przemyślany przykład (podzielony na wiele wierszy dla czytelności tutaj):
źródło
taxPayer
W tym scenariuszu nic nie mówi, że ma charakter globalny. Być może ta klasa jestTaxReturn
itaxPayer
jest atrybutem.Tak, można to wykorzystać w celu spełnienia najlepszych praktyk. Na przykład lepiej, aby funkcja o wyraźnej nazwie działała, nawet jeśli ma tylko jeden wiersz, niż mieć ten wiersz kodu w większej funkcji i potrzebować komentarza wyjaśniającego, co robi. Również sąsiednie wiersze kodu powinny wykonywać zadania na tym samym poziomie abstrakcji. Kontrprzykład byłby coś w rodzaju
W takim przypadku zdecydowanie lepiej jest przesunąć środkową linię do rozsądnie nazwanej funkcji.
źródło
petrolFlag |= 0x006A;
bez podejmowania decyzji, lepiej byłoby po prostu powiedziećpetrolFlag |= A_B_C;
bez dodatkowej funkcji. Można przypuszczać, żeengageChoke()
należy go wywołać tylko wtedy, gdypetrolFlag
spełnia określone kryteria, a to powinno wyraźnie powiedzieć „potrzebuję tutaj funkcji”. Tylko drobna nitka, ta odpowiedź jest w zasadzie na miejscu :)mixLeadedGasoline()
, nie musiałbyś!Myślę, że w wielu przypadkach taka funkcja jest dobrym stylem, ale możesz rozważyć lokalną zmienną logiczną jako alternatywę w przypadkach, gdy nie musisz używać tego warunku gdzieś w innych miejscach, np .:
To da podpowiedź dla czytnika kodów i pozwoli zaoszczędzić na wprowadzeniu nowej funkcji.
źródło
IsEngineReadyUnlessItIsOffOrBusyOrOutOfService
.).Oprócz odpowiedzi Piotra , jeśli ten warunek może wymagać aktualizacji w pewnym momencie w przyszłości, poprzez włączenie go do sposobu, w jaki sugerujesz, że będziesz miał tylko jeden punkt edycji.
Idąc za przykładem Piotra, jeśli to
staje się tym
Wykonujesz jedną edycję, która jest aktualizowana uniwersalnie. Jeśli chodzi o łatwość konserwacji, jest to plus.
Pod względem wydajności najbardziej optymalizujące kompilatory usuwają wywołanie funkcji i wstawiają mały blok kodu. Optymalizacja czegoś takiego może faktycznie zmniejszyć rozmiar bloku (poprzez usunięcie instrukcji potrzebnych do wywołania funkcji, powrotu itp.), Więc zwykle jest to bezpieczne nawet w warunkach, które w przeciwnym razie mogłyby uniemożliwić wstawianie.
źródło
seemsGreen
będzie niewiarygodny w przypadku lekkich obiektów, nie będzie miał znaczenia, jeśli kod nigdy nie będzie obchodził, czy lekkie obiekty są zielone. Jeśli jednak definicja „lekkiej” ulegnie zmianie, tak że niektóre niezielone obiekty, które zwracają wartość true,seemsGreen
nie są zgłaszane jako „lekkiej”, wówczas taka zmiana w definicji „lekkiej” może złamać kod testujący obiekty byc zielonym". W niektórych przypadkach jednoczesne testowanie zieloności i wagi w kodzie może sprawić, że związek między testami będzie wyraźniejszy niż w przypadku oddzielnych metod.Oprócz czytelności (lub jej uzupełnienia) pozwala to pisać funkcje na odpowiednim poziomie abstrakcji.
źródło
To zależy. Czasami lepiej jest zawrzeć wyrażenie w funkcji / metodzie, nawet jeśli jest to tylko jedna linia. Jeśli czytanie jest skomplikowane lub potrzebujesz go w wielu miejscach, uważam to za dobrą praktykę. W dłuższej perspektywie łatwiej jest utrzymać, ponieważ wprowadziłeś jeden punkt zmiany i lepszą czytelność .
Czasami jednak jest to po prostu coś, czego nie potrzebujesz. Jeśli mimo wszystko wyrażenie jest łatwe do odczytania i / lub pojawia się w jednym miejscu, nie zawijaj go.
źródło
Myślę, że jeśli masz ich tylko kilka, to jest w porządku, ale problem pojawia się, gdy jest ich dużo w kodzie. A kiedy kompilator działa lub interpitor (w zależności od używanego języka) Przechodzi do tej funkcji w pamięci. Powiedzmy, że masz 3 z nich. Nie sądzę, aby komputer to zauważył, ale jeśli zaczniesz mieć 100 takich drobiazgów, system będzie musiał zarejestrować funkcje w pamięci, które są wywoływane tylko raz, a następnie nie są niszczone.
źródło
Niedawno zrobiłem dokładnie to samo w aplikacji, którą refaktoryzowałem, aby jasno określić rzeczywiste znaczenie kodu bez komentarzy:
źródło
if
krótka? To lokalne podejście (lambda) sprawia, żePaymentButton_Click
funkcja (jako całość) jest trudniejsza do odczytania. WlblCreditCardError
twoim przykładzie wydaje się być członkiem, więcHaveError
jest także predykatem (prywatnym), który jest poprawny dla obiektu. Mam tendencję do głosowania za tym, ale nie jestem programistą C #, więc się opieram.CheckInputs()
???Przeniesienie tego wiersza do dobrze nazwanej metody ułatwia odczytanie kodu. Wiele innych już o tym wspomniało („kod samodokumentujący”). Inną zaletą przeniesienia go do metody jest to, że ułatwia testowanie jednostkowe. Kiedy jest izolowany we własnej metodzie i testowany jednostkowo, możesz być pewien, że jeśli / kiedy zostanie znaleziony błąd, nie będzie w tej metodzie.
źródło
Istnieje już wiele dobrych odpowiedzi, ale warto wspomnieć o specjalnym przypadku .
Jeśli instrukcja jednowierszowa wymaga komentarza i jesteś w stanie jednoznacznie zidentyfikować (co oznacza: nazwa) jej cel, rozważ wyodrębnienie funkcji przy jednoczesnym rozszerzeniu komentarza do dokumentu API. W ten sposób sprawisz, że wywołanie funkcji będzie szybsze i łatwiejsze do zrozumienia.
Co ciekawe, to samo można zrobić, jeśli obecnie nie ma nic do zrobienia, ale potrzebny jest komentarz przypominający o rozszerzeniach (w najbliższej przyszłości 1) ), więc to,
równie dobrze mógł się w to zmienić
1) powinieneś być tego pewien (patrz zasada YAGNI )
źródło
Jeśli język to obsługuje, zwykle używam do tego celu anonimowych funkcji z etykietami.
IMHO jest to dobry kompromis, ponieważ daje korzyść z czytelności, ponieważ nie ma skomplikowanego wyrażenia zaśmiecającego
if
warunek, jednocześnie unikając zaśmiecania przestrzeni nazw globalnych / pakietów małymi etykietami wyrzucania. Dodatkową zaletą jest to, że funkcja „definicja” jest odpowiednia tam, gdzie jest używana, co ułatwia modyfikację i odczyt definicji.Nie muszą to być tylko funkcje predykatów. Lubię też umieszczać powtarzające się płytki kotła w małych funkcjach takich jak ta (działa szczególnie dobrze w przypadku generowania listy pythonowej bez zaśmiecania składni nawiasu). Na przykład poniższy uproszczony przykład podczas pracy z PIL w Pythonie
źródło
[] == False
ani w żaden inny sposób podobna pythoniczna równoważność, która nie zawsze jest intuicyjna. Jest to w zasadzie sposób na oznaczenie, że someCondition jest w rzeczywistości predykatem.[] != False
ale[]
jest False jako kiedy rzucić do boollen([complicated expression producing a list]) == 0
, niż używać,True if [blah] else False
co nadal wymaga od czytelnika wiedzy, że [] to False.