Eu tenho uma interface genérica
public interface Consumer<E> {
public void consume(E e);
}
Eu tenho uma classe que consome dois tipos de objetos, então eu gostaria de fazer algo como:
public class TwoTypesConsumer implements Consumer<Tomato>, Consumer<Apple>
{
public void consume(Tomato t) { ..... }
public void consume(Apple a) { ...... }
}
Aparentemente, não posso fazer isso.
Obviamente, eu mesmo posso implementar o envio, por exemplo
public class TwoTypesConsumer implements Consumer<Object> {
public void consume(Object o) {
if (o instanceof Tomato) { ..... }
else if (o instanceof Apple) { ..... }
else { throw new IllegalArgumentException(...) }
}
}
Mas estou procurando a solução de verificação e despacho de tipos em tempo de compilação que os genéricos fornecem.
A melhor solução que posso pensar é definir interfaces separadas, por exemplo
public interface AppleConsumer {
public void consume(Apple a);
}
Funcionalmente, esta solução está bem, eu acho. É apenas verboso e feio.
Alguma ideia?
java
generics
interface
multiple-inheritance
daphshez
fonte
fonte
Respostas:
Considere o encapsulamento:
Se a criação dessas classes internas estáticas o incomoda, você pode usar classes anônimas:
fonte
TwoTypesConsumer
cumpre contratos, então qual é o objetivo? Não pode ser passado para um método que deseja um ou outro tipo de . A idéia inteira de um consumidor de dois tipos seria que você pode aplicá-lo a um método que deseja um consumidor de tomate e a um método que deseja um consumidor de maçã. Aqui não temos nenhum.Consumer
TwoTypesConsumer
instância envolvente, se necessário, e então você pode passartwoTypesConsumer.getAppleConsumer()
para um método que deseja um consumidor da Apple. Outra opção seria adicionar métodos semelhantesaddConsumer(Producer<Apple> producer)
ao TwoTypesConsumer.ExceptionMapper
) ...Por causa do apagamento do tipo, você não pode implementar a mesma interface duas vezes (com parâmetros de tipo diferentes).
fonte
Aqui está uma possível solução baseada na de Steve McLeod :
O requisito implícito da pergunta era
Consumer<Tomato>
eConsumer<Apple>
objetos que compartilham estado. A necessidade deConsumer<Tomato>, Consumer<Apple>
objetos vem de outros métodos que os esperam como parâmetros. Eu preciso de uma classe para implementar os dois para compartilhar o estado.A ideia de Steve era usar duas classes internas, cada uma implementando um tipo genérico diferente.
Esta versão adiciona getters para os objetos que implementam a interface Consumer, que podem ser passados para outros métodos que os esperam.
fonte
Consumer<*>
instâncias nos campos de instância, seget*Consumer
for chamado com frequência.Pelo menos, você pode fazer uma pequena melhoria na implementação do despacho fazendo algo como o seguinte:
Frutas sendo um ancestral do tomate e da maçã.
fonte
apenas tropeçou nisso. Aconteceu que eu tinha o mesmo problema, mas resolvi de uma maneira diferente: acabei de criar uma nova interface como esta
infelizmente, isso é considerado como
Consumer<A>
e NÃOConsumer<B>
contra toda a lógica. Então você precisa criar um pequeno adaptador para o segundo consumidor como esse dentro da sua classese
Consumer<A>
for necessário, você pode simplesmente passarthis
e, seConsumer<B>
necessário, basta passarconsumerAdapter
fonte
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.
Qualquer outra solução para empacotar as mesmas operações de consumo em uma classe requer definir sua classe como:
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:
Se, na realidade, esses tipos são realmente acoplados (relacionados), eu recomendaria criar uma implementação da seguinte maneira:
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:
Você tem:
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.
fonte
No estilo Funcional, é bastante fácil fazer isso sem implementar a interface e também faz a verificação do tipo de tempo de compilação.
Nossa interface funcional para consumir entidade
nosso gerente para processar e consumir a entidade adequadamente
fonte
Outra alternativa para evitar o uso de mais classes. (exemplo usando java8 +)
fonte
Desculpe por responder perguntas antigas, mas eu realmente adoro! Tente esta opção:
Eu acho que é isso que você está procurando.
Você obtém esta saída:
fonte