Projektuję interfejs za pomocą dwóch powiązanych metod, podobnych do tego:
public interface ThingComputer {
default Thing computeFirstThing() {
return computeAllThings().get(0);
}
default List<Thing> computeAllThings() {
return ImmutableList.of(computeFirstThing());
}
}
Około połowa implementacji obliczy tylko jedną rzecz, podczas gdy druga połowa może obliczyć więcej.
Czy ma to jakiś precedens w powszechnie używanym kodzie Java 8? Wiem, że Haskell robi podobne rzeczy w niektórych klasach ( Eq
na przykład).
Plusem jest to, że muszę pisać znacznie mniej kodu niż gdybym miał dwie abstrakcyjne klasy ( SingleThingComputer
i MultipleThingComputer
).
Minusem jest to, że pusta implementacja kompiluje się, ale wysadza w czasie działania za pomocą StackOverflowError
. Możliwe jest wykrycie wzajemnej rekurencji za pomocą a ThreadLocal
i podanie ładniejszego błędu, ale to dodaje narzut na kod bez błędów.
java
design
interfaces
java8
Tavian Barnes
źródło
źródło
throw new Error();
lub coś głupiego, tylko że sam interfejs nie powinien mieć kruchej umowy poprzezdefault
metody.abstract
istnieje, aby zmusić ich do rozwiązania problemu.Odpowiedzi:
TL; DR: nie rób tego.
To, co tu pokazujesz, to kruchy kod.
Interfejs to umowa. Mówi: „niezależnie od tego, jaki obiekt otrzymujesz, może wykonać X i Y”. Jak to jest napisane, twój interfejs robi ani X ani Y, ponieważ jest gwarantowane , aby spowodować przepełnienie stosu.
Zgłoszenie błędu lub podklasy oznacza poważny błąd, którego nie należy wychwytywać:
Ponadto VirtualMachineError , klasa nadrzędna StackOverflowError , mówi:
Twój program nie powinien zajmować się zasobami JVM . To jest zadanie JVM. Wykonanie programu, który powoduje błąd JVM w ramach normalnej pracy, jest złe. Gwarantuje to awarię programu lub zmusza użytkowników tego interfejsu do wychwytywania błędów, których nie powinien się przejmować.
Być może znasz Erica Lipperta z takich przedsięwzięć, jak emerytowany „członek komitetu projektowego w języku C #”. Mówi o cechach językowych popychających ludzi do sukcesu lub porażki: chociaż nie jest to cecha językowa ani część projektowania języka, jego punkt widzenia jest równie ważny, jeśli chodzi o implementację interfejsów lub używanie obiektów.
Źródło: C ++ i Pit Of Despair
Posiadanie interfejsu
StackOverflowError
domyślnie wpycha programistów w Pit of Despair i jest złym pomysłem . Zamiast tego popchnij programistów w stronę Pit of Success . Sprawiają, że jest łatwy w użyciu interfejs prawidłowo i bez awarii JVM.Delegowanie między metodami jest tutaj w porządku. Jednak zależność powinna iść w jedną stronę. Lubię myśleć o delegowaniu metod jak o ukierunkowanym grafie . Każda metoda jest węzłem na wykresie. Za każdym razem, gdy metoda wywołuje inną metodę, narysuj przewagę od metody wywołującej do metody wywoływanej.
Jeśli narysujesz wykres i zauważysz, że jest on cykliczny, będzie to zapach kodu. Jest to potencjał popychania programistów do Pit of Despair. Należy pamiętać, że nie powinno to być kategorycznie zabronione, należy jedynie zachować ostrożność . Algorytmy rekurencyjne będą miały cykle na wykresie połączeń: to dobrze. Dokumentuj to i ostrzegaj programistów. Jeśli nie jest rekurencyjny, spróbuj przerwać ten cykl. Jeśli nie możesz, dowiedz się, jakie dane wejściowe mogą spowodować przepełnienie stosu i albo złagodź je, albo udokumentuj jako ostatni przypadek, jeśli nic więcej nie zadziała.
źródło