Я проектирую интерфейс с двумя связанными методами, подобными этому:
public interface ThingComputer {
default Thing computeFirstThing() {
return computeAllThings().get(0);
}
default List<Thing> computeAllThings() {
return ImmutableList.of(computeFirstThing());
}
}
Приблизительно половина реализаций будет когда-либо вычислять только одну вещь, тогда как другая половина может вычислять больше.
Есть ли у этого прецедент в широко используемом коде Java 8? Я знаю, что Haskell делает подобные вещи в некоторых классах типов ( Eq
например).
Плюс в том, что мне приходится писать значительно меньше кода, чем если бы у меня было два абстрактных класса ( SingleThingComputer
и MultipleThingComputer
).
Недостатком является то, что пустая реализация компилируется, но взрывается во время выполнения с помощью a StackOverflowError
. Можно обнаружить взаимную рекурсию с помощью a ThreadLocal
и дать более приятную ошибку, но это добавляет издержки к не глючному коду.
источник
throw new Error();
или делать что-то глупое, только то, что сам интерфейс не должен иметь хрупкого контракта черезdefault
методы.abstract
существует, чтобы заставить их решить ее.Ответы:
TL; DR: не делай этого.
То, что вы показываете здесь, является хрупким кодом.
Интерфейс - это контракт. Он говорит «независимо от того, какой объект вы получаете, он может делать X и Y». Как написано, ваш интерфейс не делает ни X, ни Y, потому что он гарантированно вызовет переполнение стека.
Создание ошибки или подкласса указывает на серьезную ошибку, которая не должна быть обнаружена:
Кроме того, VirtualMachineError , родительский класс StackOverflowError , говорит следующее:
Ваша программа не должна быть связана с ресурсами JVM . Это работа JVM. Создание программы, которая вызывает ошибку JVM как часть нормальной работы, плохо. Это либо гарантирует сбой вашей программы, либо вынуждает пользователей этого интерфейса перехватывать ошибки, о которых не следует беспокоиться.
Возможно, вы знакомы с Эриком Липпертом по таким начинаниям, как почетный «член комитета по разработке языка C #». Он говорит о языковых особенностях, подталкивающих людей к успеху или неудаче: хотя это не языковая функция или часть языкового дизайна, его точка зрения одинаково верна, когда речь идет о реализации интерфейсов или использовании объектов.
Источник: C ++ и Яма Отчаяния
Наличие интерфейса
StackOverflowError
по умолчанию бросает разработчиков в Pit of Despair, и это плохая идея . Вместо этого подталкивайте разработчиков к Яме Успеха . Сделать это легко , чтобы правильно и без сбоев в JVM использовать интерфейс.Делегирование между методами здесь хорошо. Однако зависимость должна идти в одном направлении. Мне нравится думать о делегировании методов как о ориентированном графе . Каждый метод является узлом на графике. Каждый раз, когда метод вызывает другой метод, рисуйте грань от вызывающего метода до вызываемого метода.
Если вы рисуете график и замечаете, что он циклический, это - запах кода. Это может подтолкнуть разработчиков в Яму Отчаяния. Обратите внимание, что это не должно быть категорически запрещено, нужно только соблюдать осторожность . В частности, рекурсивные алгоритмы будут иметь циклы в графе вызовов: это нормально. Документируйте это и предупреждайте разработчиков. Если это не рекурсивно, попробуйте разорвать этот цикл. Если вы не можете, выясните, какие входные данные могут вызвать переполнение стека, или либо уменьшите их, либо задокументируйте это как последний случай, если больше ничего не будет работать.
источник