Це неможливо зробити безпосередньо в одному класі, оскільки визначення класу нижче не може бути скомпільовано через стирання загальних типів та дублювання декларації інтерфейсу.
class TwoTypesConsumer implements Consumer<Apple>, Consumer<Tomato> {
// cannot compile
...
}
Будь-яке інше рішення для пакування одних і тих же споживчих операцій в одному класі вимагає визначити свій клас як:
class TwoTypesConsumer { ... }
що безглуздо, оскільки вам потрібно повторювати / дублювати визначення обох операцій, і вони не будуть посилатися на інтерфейс. ІМХО, що робить це, є поганим малим копіюванням коду, якого я намагаюся уникати.
Це може бути показником також того, що в одному класі є занадто велика відповідальність за споживання двох різних об'єктів (якщо вони не пов'язані між собою).
Однак те, що я роблю, і те, що ви можете зробити, - це додати явний заводський об’єкт для створення підключених споживачів наступним чином:
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 внутрішніх класи, але у випадку виклику вам потрібно спочатку звернутися до відповідного споживача, що впроваджує, оскільки це не може бути просто одним об’єктом споживача.