У меня общий интерфейс
public interface Consumer<E> {
public void consume(E e);
}
У меня есть класс, который использует два типа объектов, поэтому я хотел бы сделать что-то вроде:
public class TwoTypesConsumer implements Consumer<Tomato>, Consumer<Apple>
{
public void consume(Tomato t) { ..... }
public void consume(Apple a) { ...... }
}
Видимо, я не могу этого сделать.
Конечно, я могу осуществить отправку самостоятельно, например
public class TwoTypesConsumer implements Consumer<Object> {
public void consume(Object o) {
if (o instanceof Tomato) { ..... }
else if (o instanceof Apple) { ..... }
else { throw new IllegalArgumentException(...) }
}
}
Но я ищу решение для проверки и диспетчеризации типов во время компиляции, которое предоставляют дженерики.
Лучшее решение, которое я могу придумать, - это определить отдельные интерфейсы, например
public interface AppleConsumer {
public void consume(Apple a);
}
Функционально, это решение хорошо, я думаю. Это просто многословно и безобразно.
Любые идеи?
java
generics
interface
multiple-inheritance
daphshez
источник
источник
Ответы:
Рассмотрим инкапсуляцию:
Если создание этих статических внутренних классов вас беспокоит, вы можете использовать анонимные классы:
источник
TwoTypesConsumer
выполняет никаких контрактов, так какой смысл? Это не может быть передано методу, который хочет любой типConsumer
. Вся идея потребителя двух типов заключается в том, что вы можете передать его методу, который хочет потребителя томатов, а также методу, который хочет потребителя яблок. Здесь у нас нет ни того, ни другого.TwoTypesConsumer
экземпляру при необходимости, а затем вы можете перейтиtwoTypesConsumer.getAppleConsumer()
к методу, который хочет потребителя Apple. Другой вариант - добавить методы, похожиеaddConsumer(Producer<Apple> producer)
на TwoTypesConsumer.ExceptionMapper
) ...Из-за стирания типа вы не можете реализовать один и тот же интерфейс дважды (с разными параметрами типа).
источник
Вот возможное решение на основе решения Стива Маклеода :
Неявным требованием этого вопроса были
Consumer<Tomato>
иConsumer<Apple>
объекты, которые разделяют состояние. Потребность вConsumer<Tomato>, Consumer<Apple>
объектах исходит от других методов, которые ожидают их в качестве параметров. Мне нужен один класс, чтобы реализовать их оба, чтобы поделиться государством.Идея Стива состояла в том, чтобы использовать два внутренних класса, каждый из которых реализовывал свой общий тип.
В этой версии добавлены методы получения объектов, реализующих интерфейс Consumer, которые затем можно передать другим ожидающим их методам.
источник
Consumer<*>
экземпляры в полях экземпляров, еслиget*Consumer
вызывается часто.По крайней мере, вы можете сделать небольшое улучшение в своей реализации диспетчеризации, выполнив что-то вроде следующего:
Фрукты, являющиеся предками помидоров и яблок.
источник
просто наткнулся на это. Случилось так, что у меня возникла та же проблема, но я решил ее по-другому: я просто создал новый интерфейс, подобный этому
к сожалению, это считается как
Consumer<A>
и НЕConsumer<B>
против всей логики. Таким образом, вы должны создать небольшой адаптер для второго потребителя, как это в вашем классеесли
Consumer<A>
требуется, вы можете просто пройтиthis
, а еслиConsumer<B>
нужно, просто передатьconsumerAdapter
источник
Вы не можете сделать это напрямую в одном классе, так как приведенное ниже определение класса не может быть скомпилировано из-за удаления универсальных типов и дублирования объявления интерфейса.
Любое другое решение для упаковки одинаковых операций потребления в одном классе требует определения вашего класса как:
что бессмысленно, так как вам нужно повторять / дублировать определение обеих операций, и они не будут ссылаться из интерфейса. ИМХО это плохое маленькое дублирование кода, которого я пытаюсь избежать.
Это также может быть показателем того, что в одном классе слишком много ответственности, чтобы потреблять 2 разных объекта (если они не связаны).
Однако, что я делаю и что вы можете сделать, это добавить явный объект фабрики для создания подключенных потребителей следующим образом:
Если в действительности эти типы действительно связаны (связаны), я бы рекомендовал создать реализацию следующим образом:
Преимущество состоит в том, что фабричный класс знает обе реализации, существует общее состояние (если необходимо), и вы можете вернуть больше связанных потребителей, если это необходимо. Нет повторяющегося объявления метода потребления, который не является производным от интерфейса.
Обратите внимание, что каждый потребитель может быть независимым (все еще частным) классом, если он не полностью связан.
Недостатком этого решения является более высокая сложность класса (даже если это может быть один Java-файл), и для доступа к методу потребления вам потребуется еще один вызов, вместо:
у тебя есть:
Подводя итог, вы можете определить 2 общих потребителя в одном классе верхнего уровня, используя 2 внутренних класса, но в случае вызова вам нужно сначала получить ссылку на соответствующего реализующего потребителя, поскольку это не может быть просто один объект потребителя.
источник
В функциональном стиле это довольно легко сделать без реализации интерфейса, а также он выполняет проверку типов во время компиляции.
Наш функциональный интерфейс для использования сущности
наш менеджер, чтобы обработать и потреблять сущность соответствующим образом
источник
Еще одна альтернатива, чтобы избежать использования большего количества классов. (пример использования java8 +)
источник
Извините за ответы на старые вопросы, но мне это очень нравится! Попробуйте этот вариант:
Я думаю, это то, что вы ищете.
Вы получаете этот вывод:
источник