Tengo una situación inesperada en un proyecto en el que todos los tipos que extienden una clase se empaquetan en una colección Java; pero solo una extensión específica de esa clase contiene un método adicional. Llamémoslo "también ()"; y déjenme aclarar que ninguna otra extensión lo tiene. Justo antes de realizar una tarea en cada elemento de esa colección, necesito llamar también () a cada elemento que lo implemente.
La forma más fácil de avanzar es esta:
stuff.stream().filter(item -> item instanceof SpecificItem)
.forEach(item -> ((SpecificItem)item).also()));
stuff.stream().forEach(item -> item.method());
Funciona bien, pero no me siento cómodo con la "instancia de" allí. Eso generalmente es un marcador de mal olor del código. Es muy posible que refactorice esta clase solo para deshacerme de ella. Sin embargo, antes de hacer algo tan dramático, pensé en consultar con la comunidad y ver si alguien con más experiencia con Streams o Collections tenía una solución más simple.
Como ejemplo (ciertamente no exclusivo), ¿es posible obtener una vista de una colección que filtre las entradas por clase?
fuente
SpecificItem
, y esta es la forma correcta de especificar el predicado, entonces, ¿por qué le preocupa tantoinstanceof
estar allí?.getKind()
o.isSpecific()
?SpecificItem
la implementación no solo llamealso()
primero?Iterable
no tiene unstream()
método, pero puede llamarforEach()
directamente a unIterable
.Respuestas:
Te sugiero que
.map
llames para hacer el reparto por ti. Entonces su código posterior puede usar la 'cosa real'.Antes de:
Después:
Esto no es perfecto, pero parece limpiar un poco las cosas.
fuente
stuff.stream().filter(item -> item instanceof SpecificItem).map(SpecificItem.class::cast).forEach(SpecificItem::also);
Obviamente es un diseño defectuoso. Por lo que escribió no está claro, lo que significa, que una clase no implementa el método. Si simplemente no hace nada , no importaría, así que supongo que hay un efecto secundario no deseado.
Tus agallas son correctas. Un buen diseño orientado a objetos funcionaría sin mayor conocimiento de qué es exactamente un objeto, o si se trata de una instancia de un tipo especial.
Refactorizar no es dramático. Mejora la calidad del código.
Con su base de código dada, la solución más simple sería, para asegurarse, tener dos colecciones separadas, una con la clase principal y otra con la clase secundaria. Pero eso no está del todo limpio.
fuente
Es difícil dar recomendaciones específicas sin saber qué son
SpecificItem
y quéalso()
son en realidad, pero:Definir
also()
en la superclase deSpecificItem
. Dale una implementación predeterminada que no haga nada (dale un cuerpo de método vacío). Las subclases individuales pueden anularlo si lo desea. Dependiendo de lo quealso
realmente es, es posible que deba cambiarle el nombre a algo que tenga sentido para todas las clases involucradas.fuente
una alternativa:
de esa manera solo los objetos que implementan su interfaz podrían pasar temas a su método ... no es necesario usar instanceof
fuente
Espero que no me falte nada obvio aquí (también como lo sugiere el comentario de @Tristan Burnside ), pero ¿por qué no puedo
SpecificItem.method()
llamaralso()
primero?Una forma fluida en la que puedo pensar, a expensas de tal vez algún impacto en el rendimiento (YMMV), es a
collect()
travésCollectors.groupingBy()
de la clase como la clave, y luego elegir lo que desea del resultadoMap
. Los valores se almacenan como aList
, por lo que si esperaba hacer un filtrado de este tipo enSet
y espera obtener un filtroSet
, entonces necesitará un paso adicional para poner los valores en un resultadoSet
también.fuente
Aquí está mi enfoque:
Sin instancia de , no hay conversiones explícitas (en realidad es una conversión explícita, pero enmascarada por una llamada al método). Creo que esto es tan bueno como puede ser.
fuente