Tengo una interfaz genérica
public interface Consumer<E> {
public void consume(E e);
}
Tengo una clase que consume dos tipos de objetos, por lo que me gustaría hacer algo como:
public class TwoTypesConsumer implements Consumer<Tomato>, Consumer<Apple>
{
public void consume(Tomato t) { ..... }
public void consume(Apple a) { ...... }
}
Aparentemente no puedo hacer eso.
Por supuesto, puedo implementar el envío yo mismo, por ejemplo
public class TwoTypesConsumer implements Consumer<Object> {
public void consume(Object o) {
if (o instanceof Tomato) { ..... }
else if (o instanceof Apple) { ..... }
else { throw new IllegalArgumentException(...) }
}
}
Pero estoy buscando la solución de verificación y envío de tipos en tiempo de compilación que ofrecen los genéricos.
La mejor solución que se me ocurre es definir interfaces separadas, p. Ej.
public interface AppleConsumer {
public void consume(Apple a);
}
Funcionalmente, esta solución está bien, creo. Es simplemente detallado y feo.
¿Algunas ideas?
java
generics
interface
multiple-inheritance
daphshez
fuente
fuente
Respuestas:
Considere la encapsulación:
Si crear estas clases internas estáticas te molesta, puedes usar clases anónimas:
fuente
TwoTypesConsumer
cumple ningún contrato, ¿cuál es el punto? No se puede pasar a un método que quiera cualquier tipo deConsumer
. La idea general de un consumidor de dos tipos sería que se lo puede dar a un método que quiere un consumidor de tomate, así como a un método que quiere un consumidor de manzana. Aquí no tenemos ninguno.TwoTypesConsumer
instancia de cierre si es necesario, y luego puede pasartwoTypesConsumer.getAppleConsumer()
a un método que quiera un consumidor de manzanas. Otra opción sería agregar métodos similaresaddConsumer(Producer<Apple> producer)
a TwoTypesConsumer.ExceptionMapper
) ...Debido a la eliminación de tipo, no puede implementar la misma interfaz dos veces (con diferentes parámetros de tipo).
fuente
Aquí hay una posible solución basada en la de Steve McLeod :
El requisito implícito de la pregunta era
Consumer<Tomato>
y losConsumer<Apple>
objetos que comparten el estado. La necesidad deConsumer<Tomato>, Consumer<Apple>
objetos proviene de otros métodos que esperan estos como parámetros. Necesito una clase para implementar ambos para compartir el estado.La idea de Steve era usar dos clases internas, cada una implementando un tipo genérico diferente.
Esta versión agrega captadores para los objetos que implementan la interfaz del consumidor, que luego se pueden pasar a otros métodos que los esperan.
fuente
Consumer<*>
instancias en los campos de instancia siget*Consumer
se llama con frecuencia.Al menos, puede hacer una pequeña mejora en su implementación del despacho haciendo algo como lo siguiente:
La fruta es un antepasado del tomate y la manzana.
fuente
me topé con esto. Simplemente sucedió que tenía el mismo problema, pero lo resolví de una manera diferente: acabo de crear una nueva interfaz como esta
desafortunadamente, esto se considera como
Consumer<A>
y NO comoConsumer<B>
contra toda lógica. Por lo tanto, debe crear un pequeño adaptador para el segundo consumidor como este dentro de su clasesi
Consumer<A>
es necesario, simplemente puede pasarthis
, y siConsumer<B>
es necesario, simplemente paseconsumerAdapter
fuente
No puede hacer esto directamente en una clase ya que la definición de clase a continuación no se puede compilar debido a la eliminación de tipos genéricos y la declaración de interfaz duplicada.
Cualquier otra solución para empacar las mismas operaciones de consumo en una clase requiere definir su clase como:
lo cual no tiene sentido ya que necesita repetir / duplicar la definición de ambas operaciones y no se hará referencia a ellas desde la interfaz. En mi humilde opinión, hacer esto es una pequeña duplicación de código y mal que estoy tratando de evitar.
Esto podría ser un indicador también de que hay demasiada responsabilidad en una clase para consumir 2 objetos diferentes (si no están acoplados).
Sin embargo, lo que estoy haciendo y lo que puede hacer es agregar un objeto de fábrica explícito para crear consumidores conectados de la siguiente manera:
Si en realidad esos tipos están realmente acoplados (relacionados), recomendaría crear una implementación de esta manera:
La ventaja es que la clase de fábrica conoce ambas implementaciones, hay un estado compartido (si es necesario) y puede devolver más consumidores acoplados si es necesario. No hay declaración de método de consumo repetitivo que no se derive de la interfaz.
Tenga en cuenta que cada consumidor puede ser una clase independiente (aún privada) si no están completamente relacionados.
La desventaja de esa solución es una mayor complejidad de clase (incluso si este puede ser un archivo java) y para acceder al método de consumo necesita una llamada más, en lugar de:
tienes:
Para resumir, puede definir 2 consumidores genéricos en una clase de nivel superior utilizando 2 clases internas, pero en caso de llamar, primero debe obtener una referencia al consumidor de implementación apropiado , ya que este no puede ser simplemente un objeto de consumidor.
fuente
En el estilo funcional, es bastante fácil hacerlo sin implementar la interfaz y también realiza la comprobación del tipo de tiempo de compilación.
Nuestra interfaz funcional para consumir entidad
nuestro gerente para procesar y consumir la entidad adecuadamente
fuente
Otra alternativa para evitar el uso de más clases. (ejemplo usando java8 +)
fuente
Perdón por responder viejas preguntas, ¡pero realmente me encanta! Prueba esta opción:
Creo que eso es lo que estás buscando.
Obtienes esta salida:
fuente