Você não pode fazer isso diretamente em uma classe, pois a definição de classe abaixo não pode ser compilada devido ao apagamento de tipos genéricos e à declaração de interface duplicada.
class TwoTypesConsumer implements Consumer<Apple>, Consumer<Tomato> {
// cannot compile
...
}
Qualquer outra solução para empacotar as mesmas operações de consumo em uma classe requer definir sua classe como:
class TwoTypesConsumer { ... }
o que é inútil, pois você precisa repetir / duplicar a definição de ambas as operações e elas não serão referenciadas na interface. IMHO fazer isso é uma duplicação ruim de código e pequeno que estou tentando evitar.
Isso também pode ser um indicador de que existe muita responsabilidade em uma classe para consumir 2 objetos diferentes (se não estiverem acoplados).
No entanto, o que estou fazendo e o que você pode fazer é adicionar um objeto de fábrica explícito para criar consumidores conectados da seguinte maneira:
interface ConsumerFactory {
Consumer<Apple> createAppleConsumer();
Consumer<Tomato> createTomatoConsumer();
}
Se, na realidade, esses tipos são realmente acoplados (relacionados), eu recomendaria criar uma implementação da seguinte maneira:
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();
}
}
A vantagem é que a classe factory conhece as duas implementações, existe um estado compartilhado (se necessário) e você pode retornar mais consumidores acoplados, se necessário. Não há nenhuma declaração repetida do método de consumo que não seja derivada da interface.
Observe que cada consumidor pode ser de classe independente (ainda privada) se não estiver completamente relacionado.
A desvantagem dessa solução é uma complexidade de classe mais alta (mesmo que possa ser um arquivo java) e para acessar o método de consumo, você precisa de mais uma chamada, em vez de:
twoTypesConsumer.consume(apple)
twoTypesConsumer.consume(tomato)
Você tem:
twoTypesConsumerFactory.createAppleConsumer().consume(apple);
twoTypesConsumerFactory.createTomatoConsumer().consume(tomato);
Para resumir, você pode definir 2 consumidores genéricos em uma classe de nível superior usando 2 classes internas, mas, no caso de chamar, é necessário primeiro obter uma referência ao consumidor de implementação apropriado, pois esse não pode ser simplesmente um objeto de consumidor.