Jeśli istnieje metoda
bool DoStuff() {
try {
// doing stuff...
return true;
}
catch (SomeSpecificException ex) {
return false;
}
}
czy raczej powinno się to nazywać IsStuffDone()
?
Obie nazwy mogą zostać błędnie zinterpretowane przez użytkownika: Jeśli nazwa jest DoStuff()
przyczyną, dla której zwraca wartość logiczną? Jeśli nazwa brzmi, IsStuffDone()
nie jest jasne, czy metoda wykonuje zadanie, czy tylko sprawdza jego wynik.
Czy istnieje konwencja w tej sprawie? Lub podejście alternatywne, ponieważ uważa się je za wadliwe? Na przykład w językach, które mają parametry wyjściowe, takie jak C #, boolowska zmienna statusu może być przekazana do metody jako jedna, a typem zwracanej metody będzie void
.
EDYCJA: W moim konkretnym problemie obsługa wyjątków nie może być bezpośrednio delegowana do programu wywołującego, ponieważ metoda jest częścią implementacji interfejsu. W związku z tym osoba dzwoniąca nie może być obciążona zajmowaniem się wszystkimi wyjątkami różnych implementacji. Nie zna tych wyjątków. Jednak osoba dzwoniąca może poradzić sobie z niestandardowym wyjątkiem, takim StuffHasNotBeenDoneForSomeReasonException
jak zasugerowano w odpowiedzi i komentarzu npinti .
źródło
boolean
zamiast owijania lub przekazywania wyjątku jest prawie zawsze błędne.BadlyDesignedMethodInSeriousNeedOfRefactoring
? I aby odpowiedzieć na twoje pytanie dotyczące wyjątków - albo pozwól abonentowi je obsłużyć, albo złapię je, a następnie wyrzucę niestandardowy wyjątek, który oznacza, że „ta metoda nie działa”. Udostępnij i ciesz się.if (FirstMethodSucceeds(problem) or SecondMethodSucceeds(problem) or ...) Hurray(); else UniversalSolve(problem);
. To samo z wyjątkami (niestandardowymi?) Byłoby bezużytecznie bardziej skomplikowane.Odpowiedzi:
W .NET często masz pary metod, z których jedna może zgłosić wyjątek (
DoStuff
), a druga zwraca wartość logiczną, a po pomyślnym wykonaniu rzeczywisty wynik za pomocą parametru out (TryDoStuff
).(Microsoft nazywa to „Wzorem Try-Parse” , ponieważ być może najbardziej znanym przykładem są
TryParse
metody różnych pierwotnych typów).Jeśli
Try
prefiks jest rzadki w twoim języku, prawdopodobnie nie powinieneś go używać.źródło
if (TryDoStuff()) print("Did stuff"); else print("Could not do stuff");
jest moim zdaniem dość standardowym i intuicyjnym idiomem.TryDoStuff
zakłada się , że metody zawodzą w sposób czysty i nie powodują żadnych skutków ubocznych, gdy zwracają wartość false.Remove
metody, na przykład w .NET Framework, które usuwają element ze struktury danych (np.Dictionary
) I zwracają abool
. Konsument interfejsu API może zdecydować o jego zużyciu lub zignorowaniu. Błędy są jednak zgłaszane jako wyjątki.Co jeśli po prostu rzucisz wyjątek na kod wywołujący?
W ten sposób przekazujesz obsługę wyjątków komukolwiek, kto kiedykolwiek używa Twojego kodu. Co jeśli w przyszłości chcesz wykonać następujące czynności:
FileNotFoundException
zostanie wyrzucony a, wykonaj działanie BJeśli odrzucisz swój wyjątek, powyższa zmiana po prostu pociągnie za sobą dodanie dodatkowego
catch
bloku. Jeśli pozostawisz go takim, jakim jest, musisz zmienić metodę i miejsce, z którego ta metoda jest wywoływana, co w zależności od złożoności projektu może znajdować się w wielu lokalizacjach.źródło
DoStuff
awaria jest powszechna lub normalna , zgłoszenie wyjątku w przypadku awarii byłoby podobne do kontrolowania przepływu programu z wyjątkami, które są złe. Wyjątki mają również nieodłączny koszt wydajności. JeśliDoStuff
niepowodzenie jest rzadkim przypadkiem z powodu błędu, wyjątki są zdecydowanie sposobem, jak sugeruje @npinti.DoStuff()
metoda OP zostanie wyczyszczona po tym, jak wewnętrzny kod zgłosi wyjątek, a warunki końcowe metody są nadal poprawne, kod powrotu może być lepszą opcją, ponieważ błąd został rozwiązany.DoStuff()
wystarczy, a zwracana wartość funkcji powinna zostać udokumentowana i nie trzeba jej wymieniać w nazwie funkcji, szukając wielu dostępnych API:PHP
C-Sharp
źródło
W Javie interfejs API kolekcji definiuje metodę add, która zwraca wartość logiczną. Zasadniczo zwraca, czy dodatek zmienił kolekcję. Tak więc dla a
List
zwykle zwróci true, ponieważ element został dodany, a dla aSet
może zwrócić false, jeśli element już tam był, ponieważSet
s dopuszcza każdy unikalny element najwyżej.To powiedziawszy, jeśli dodasz element, który nie jest dozwolony przez kolekcję, na przykład wartość pustą, dodanie wyrzuci
NullPointerException
zamiast zwracać fałsz.Kiedy zastosujesz tę samą logikę do swojej sprawy, dlaczego musisz zwrócić wartość logiczną? Jeśli ma to ukryć wyjątek, nie rób tego. Po prostu rzuć wyjątek. W ten sposób możesz zobaczyć, co poszło nie tak. Jeśli potrzebujesz wartości logicznej, ponieważ mogła nie zostać wykonana z innego powodu niż wyjątek, nazwij metodę
DoStuff()
, ponieważ reprezentuje to zachowanie. Robi rzeczy.źródło
Może się nie powieść z różnych powodów, wyjątek, normalne warunki, więc skorzystam z tego:
Ważne jest udokumentowanie, co oznacza wartość logiczna.
źródło
Zwykle mam metody zwracające
OperationResult
(lubOperationResult<T>
) i odpowiednio ustawiająceIsSuccess
właściwośćOperationResult
. Jeśli „zwykła” metoda jest nieważna, zwróćOperationResult
, jeśli „zwykła” metoda zwróci obiekt, to wróćOperationResult<T>
i ustawItem
właściwośćOperationResult
odpowiednio. Sugerowałbym również posiadanie metodOperationResult
takich jak.Failed(string reason)
i.Succeeded(T item)
.OperationResult
szybko staje się typowym typem w twoich systemach, a programiści dowiadują się, jak sobie z tym poradzić.źródło
To naprawdę zależy od używanego języka. Podobnie jak w przypadku niektórych języków, istnieją konwencje i protokoły, które tak naprawdę nie istnieją w wielu językach lub w ogóle.
Na przykład w języku Objective-C i nazwach metod SDK dla iOS / Mac OS X zwykle idą w kierunku:
Jak widać, istnieje metoda o nazwie viewDidLoad. Wolę używać tego rodzaju nazewnictwa przy każdym tworzeniu własnych aplikacji. Można to wykorzystać do sprawdzenia, czy coś miało się wydarzyć, jak powiedziałeś. Uważam, że zbyt głęboko myślisz o tym, jak nazywasz swoje metody. Większość metod zwraca status, bez względu na to, co robią, na przykład:
W PHP mysql_connect () zwróci false, jeśli połączenie się nie powiedzie. Nie mówi, że tak, ale tak jest, a dokumentacja mówi, że tak, więc nie można go źle interpretować programistom.
źródło
Chciałbym zaproponować użycie prefiksu „Try”. Jest to dobrze znany wzorzec dla sytuacji, w których metoda może się powieść lub nie. Ten wzorzec nazewnictwa był używany przez Microsoft w .NET Framework (na przykład TryParseInt).
Ale może nie chodzi o nazywanie. Chodzi o to, jak projektujesz parametry wejściowe / wyjściowe metody.
Mój pomysł jest taki, że jeśli metoda ma wartość zwracaną, to celem wywołania tej metody powinno być uzyskanie tej wartości. Dlatego należy unikać używania typu zwracanego do wskazywania statusu operacji.
W języku C # wolę użyć parametru out. Używając out zaznaczam parametr jako parametr boczny. Szczególnie, że C # 6 będzie obsługiwał deklarację zmiennych wbudowanych.
źródło
Wybrałbym nazwę na podstawie podstawowej roli metody. Fakt, że ta metoda zwraca wartość logiczną, nie wymaga przedrostka „Is”. Spójrzmy na kod Java, który używa prefiksu „Is” dość szeroko. Spójrz na
java.io.File.delete()
. Zwracaboolean
, ale nie jest nazywaneisFileDeleted()
. Powodem jest to, że podstawową rolą metody jest usunięcie pliku. Ktoś wywołuje tę metodę z zamiarem usunięcia pliku.Wartość logiczna służy tylko do informowania o wyniku pracy. Z drugiej strony zobaczmy
java.util.Map.isEmpty()
. Oczywiście wywołujesz taką metodę, aby sprawdzić, czy kolekcja jest pusta. Nie chcesz robić żadnych rzeczy. Chcesz tylko dowiedzieć się, jaki jest obecny stan.Więc osobiście zdecydowanie bym się trzymał
DoStuff()
.To dla mnie bardzo ważna kwestia. Wiele razy, gdy zachowuję starszy kod, napotykam na coś, co osobiście nazywam „metodą kłamstwa”. Nazwa sugeruje działanie A, ale ciało wykonuje działanie B. Najbardziej zadziwiający przykład to metoda gettera zmieniająca dane w bazie danych.
źródło