Вы не можете сделать это напрямую в одном классе, так как приведенное ниже определение класса не может быть скомпилировано из-за удаления универсальных типов и дублирования объявления интерфейса.
class TwoTypesConsumer implements Consumer<Apple>, Consumer<Tomato> {
// cannot compile
...
}
Любое другое решение для упаковки одинаковых операций потребления в одном классе требует определения вашего класса как:
class TwoTypesConsumer { ... }
что бессмысленно, так как вам нужно повторять / дублировать определение обеих операций, и они не будут ссылаться из интерфейса. ИМХО это плохое маленькое дублирование кода, которого я пытаюсь избежать.
Это также может быть показателем того, что в одном классе слишком много ответственности, чтобы потреблять 2 разных объекта (если они не связаны).
Однако, что я делаю и что вы можете сделать, это добавить явный объект фабрики для создания подключенных потребителей следующим образом:
interface ConsumerFactory {
Consumer<Apple> createAppleConsumer();
Consumer<Tomato> createTomatoConsumer();
}
Если в действительности эти типы действительно связаны (связаны), я бы рекомендовал создать реализацию следующим образом:
class TwoTypesConsumerFactory {
// shared objects goes here
private class TomatoConsumer implements Consumer<Tomato> {
public void consume(Tomato tomato) {
// you can access shared objects here
}
}
private class AppleConsumer implements Consumer<Apple> {
public void consume(Apple apple) {
// you can access shared objects here
}
}
// It is really important to return generic Consumer<Apple> here
// instead of AppleConsumer. The classes should be rather private.
public Consumer<Apple> createAppleConsumer() {
return new AppleConsumer();
}
// ...and the same here
public Consumer<Tomato> createTomatoConsumer() {
return new TomatoConsumer();
}
}
Преимущество состоит в том, что фабричный класс знает обе реализации, существует общее состояние (если необходимо), и вы можете вернуть больше связанных потребителей, если это необходимо. Нет повторяющегося объявления метода потребления, который не является производным от интерфейса.
Обратите внимание, что каждый потребитель может быть независимым (все еще частным) классом, если он не полностью связан.
Недостатком этого решения является более высокая сложность класса (даже если это может быть один Java-файл), и для доступа к методу потребления вам потребуется еще один вызов, вместо:
twoTypesConsumer.consume(apple)
twoTypesConsumer.consume(tomato)
у тебя есть:
twoTypesConsumerFactory.createAppleConsumer().consume(apple);
twoTypesConsumerFactory.createTomatoConsumer().consume(tomato);
Подводя итог, вы можете определить 2 общих потребителя в одном классе верхнего уровня, используя 2 внутренних класса, но в случае вызова вам нужно сначала получить ссылку на соответствующего реализующего потребителя, поскольку это не может быть просто один объект потребителя.