Aby uprościć interfejs, czy lepiej nie mieć tej getBalance()
metody? Przejście 0
do charge(float c);
daje taki sam wynik:
public class Client {
private float bal;
float getBalance() { return bal; }
float charge(float c) {
bal -= c;
return bal;
}
}
Może zanotuj javadoc
? Lub po prostu pozostawić użytkownikowi klasy, aby dowiedzieć się, jak uzyskać równowagę?
interfaces
cqrs
David
źródło
źródło
Odpowiedzi:
Wydaje się, że sugerujesz, że złożoność interfejsu jest mierzona liczbą elementów, które ma (w tym przypadku metod). Wielu twierdziło, że konieczność pamiętania, że
charge
metoda może być wykorzystana do przywrócenia równowagi aClient
dodaje znacznie większej złożoności niż posiadanie dodatkowego elementugetBalance
metody. Wyjaśnienie rzeczy jest znacznie prostsze, szczególnie do tego stopnia, że nie pozostawia niejednoznaczności, niezależnie od większej liczby elementów interfejsu.Poza tym dzwonienie
charge(0)
narusza zasadę najmniejszego zdziwienia , znaną również jako metryka WTF na minutę (z Clean Code, zdjęcie poniżej), co utrudnia nowym członkom zespołu (lub obecnym, po pewnym czasie od kodu), aż rozumieją, że połączenie jest rzeczywiście wykorzystywane do uzyskania równowagi. Pomyśl, jak zareagowaliby inni czytelnicy:Ponadto podpis
charge
metody jest niezgodny z wytycznymi wykonywania jednej i tylko jednej rzeczy oraz rozdzielania poleceń i zapytań , ponieważ powoduje, że obiekt zmienia swój stan, a jednocześnie zwraca nową wartość.Podsumowując, uważam, że najprostszym interfejsem w tym przypadku byłoby:
źródło
getBalance()
zwraca pewną wartość i niczego nie modyfikuje. Z drugiej stronycharge(0)
wygląda na to, że prawdopodobnie coś modyfikuje ... może wysyła zdarzenie PropertyChanged? A co to jest, poprzednia lub nowa wartość? Teraz musisz to sprawdzić w dokumentacji i zmarnować siłę roboczą, czego można by uniknąć, stosując jaśniejszą metodę.charge(0)
jako sposobu na uzyskanie równowagi, ponieważ okazuje się, że nie ma żadnego efektu, odsyła cię teraz do tych szczegółów implementacji; Mogę łatwo wyobrazić sobie przyszły wymóg, w którym śledzenie liczby ładunków staje się istotne, w którym to momencie zaszywanie bazy kodu ładunkami, które tak naprawdę nie są ładunkami, staje się problemem. Powinieneś zapewnić elementy interfejsu, które oznaczają rzeczy, które muszą zrobić Twoi klienci, a nie takie, które po prostu robią to, czego potrzebują Twoi klienci.charge()
metody, jeśli metoda ta jest atomowa w systemie współbieżnym, może być właściwe zwrócenie nowej lub starej wartości.IMO, zastępowanie
getBalance()
wcharge(0)
całej aplikacji nie jest uproszczeniem. Tak, jest mniej wierszy, ale zaciemnia znaczeniecharge()
metody, co może potencjalnie powodować bóle głowy w dół linii, gdy ty lub ktoś inny musisz ponownie odwiedzić ten kod.Chociaż mogą dać ten sam wynik, uzyskanie salda konta nie jest równoznaczne z opłatą zerową, więc prawdopodobnie najlepiej byłoby rozdzielić swoje obawy. Na przykład, jeśli kiedykolwiek musiałeś zmodyfikować
charge()
rejestrowanie za każdym razem, gdy istnieje transakcja na koncie, masz teraz problem i i tak musisz oddzielić tę funkcję.źródło
Ważne jest, aby pamiętać, że Twój kod powinien być samodokumentujący. Kiedy dzwonię
charge(x)
, oczekujęx
obciążenia. Informacje na temat równowagi są drugorzędne. Co więcej, mogę nie wiedzieć, jakcharge()
jest zaimplementowany, kiedy go nazywam, i na pewno nie będę wiedział, jak zostanie zaimplementowany jutro. Na przykład rozważ tę potencjalną przyszłą aktualizację, abycharge()
:Nagle używanie w
charge()
celu uzyskania równowagi nie wygląda tak dobrze.źródło
charge
ma znacznie większą wagę.Używanie w
charge(0);
celu uzyskania równowagi jest złym pomysłem: pewnego dnia ktoś może dodać tam kod, aby zarejestrować naliczane opłaty, nie zdając sobie sprawy z innego wykorzystania funkcji, a następnie za każdym razem, gdy ktoś otrzyma saldo, zostanie zarejestrowany jako opłata. (Istnieją na to sposoby, takie jak warunkowe stwierdzenie, które mówi coś takiego:ale polegają one na tym, że programista umie je wdrożyć, czego nie zrobi, jeśli nie będzie od razu oczywiste, że są one konieczne.
Krótko mówiąc: nie polegaj ani na swoich użytkownikach, ani na programistach,
charge(0);
którzy zdają sobie sprawę, że jest to właściwy sposób na uzyskanie równowagi, ponieważ chyba że istnieje dokumentacja, której nie można przegapić, to szczerze mówiąc, która wygląda na najbardziej przerażający sposób na uzyskanie równowagi możliwy.źródło
Wiem, że jest wiele odpowiedzi, ale innym powodem
charge(0)
jest to, że zwykła literówkacharge(9)
spowoduje zmniejszenie salda klienta za każdym razem, gdy chcesz uzyskać równowagę. Jeśli masz dobre testy jednostkowe, możesz być w stanie zminimalizować to ryzyko, ale jeśli nie będziesz sumienny przy każdym połączeniu docharge
ciebie, możesz mieć ten wypadek.źródło
Chciałbym wspomnieć o szczególnym przypadku, gdzie to byłoby sensu mieć mniej, bardziej uniwersalnego sposoby: jeśli istnieje wiele polimorfizmu, czyli wielu implementacji tego interfejsu ; szczególnie jeśli te implementacje są w osobnym kodzie, którego nie można zaktualizować synchronicznie (interfejs jest zdefiniowany przez bibliotekę).
W takim przypadku uproszczenie zadania pisania każdej implementacji jest znacznie cenniejsze niż przejrzystość jej użycia, ponieważ ta pierwsza pozwala uniknąć błędów związanych z naruszeniem umowy (dwie metody są ze sobą niespójne), natomiast druga szkodzi jedynie czytelności, co może być odzyskane za pomocą funkcji pomocniczej lub metody nadklasy definiującej
getBalance
w kategoriachcharge
.(Jest to wzorzec projektowy, dla którego nie pamiętam konkretnej nazwy: definiowanie złożonego interfejsu przyjaznego dla dzwoniącego w kategoriach minimalnego interfejsu przyjaznego implementatorowi. W klasycznym Mac OS minimalny interfejs do operacji rysowania nazywano „wąskim gardłem” ale to nie wydaje się popularne.)
Jeśli tak nie jest (jest kilka implementacji lub dokładnie jedna), wówczas rozdzielenie metod dla jasności i umożliwienie prostego dodania zachowania istotnego dla ładunków niezerowych
charge()
ma sens.źródło
realloc
w niektórych systemach.