Eu tenho uma situação inesperada em um projeto no qual todos os tipos que estendem uma classe são compactados em uma coleção Java; mas apenas uma extensão específica dessa classe contém um método adicional. Vamos chamar de "also ()"; e deixe-me esclarecer que nenhuma outra extensão possui. Antes de executar uma tarefa em cada item dessa coleção, preciso chamar também () todos os itens que a implementam.
O caminho mais fácil é o seguinte:
stuff.stream().filter(item -> item instanceof SpecificItem)
.forEach(item -> ((SpecificItem)item).also()));
stuff.stream().forEach(item -> item.method());
Funciona bem, mas não me sinto confortável com a "instânciaof" lá. Isso geralmente é um marcador de mau cheiro de código. É muito possível que eu refatore essa classe apenas para me livrar dela. Antes de fazer algo tão dramático, pensei em verificar com a comunidade e ver se alguém com mais experiência no Streams ou no Collections tinha uma solução mais simples.
Como exemplo (certamente não exclusivo), é possível obter uma visão de uma coleção que filtra entradas por classe?
fonte
SpecificItem
, e esta é a maneira correta de especificar o predicado, então por que você é sensível sobre o fato deinstanceof
estar lá?.getKind()
ou.isSpecific()
?SpecificItem
para a implementação não chamar apenasalso()
primeiro?Iterable
não tem umstream()
método, mas você pode chamarforEach()
diretamente em umIterable
.Respostas:
Eu sugiro
.map
que faça uma ligação para fazer o elenco para você. Então seu código posterior pode usar a 'coisa real'.Antes:
Depois de:
Isso não é perfeito, mas parece limpar um pouco as coisas.
fonte
stuff.stream().filter(item -> item instanceof SpecificItem).map(SpecificItem.class::cast).forEach(SpecificItem::also);
Obviamente, esse é um design defeituoso. Pelo que você escreveu, não está claro, o que significa, que uma classe não implementa o método. Se simplesmente não fizer nada , não importaria, então presumo que exista um efeito colateral indesejado.
Suas entranhas estão certas. Um bom design orientado a objetos funcionaria sem mais conhecimento do que exatamente um objeto, ou se é uma instância de um tipo especial.
A refatoração não é dramática. Melhora a qualidade do código.
Com sua base de código fornecida, a solução mais simples seria, para garantir, você ter duas coleções separadas, uma com a classe pai e outra com a classe filho. Mas isso não é muito limpo.
fonte
É difícil dar recomendações específicas sem saber o que
SpecificItem
ealso()
realmente são, mas:Defina
also()
na superclasse deSpecificItem
. Dê a ele uma implementação padrão que não faça nada (dê um corpo de método vazio). Subclasses individuais podem substituí-lo, se desejado. Dependendo do quealso
realmente é, pode ser necessário renomeá-lo para algo que faça sentido para todas as classes envolvidas.fonte
uma alternativa:
Dessa forma, apenas objetos que implementam sua interface poderiam passar temas para o seu método ... não há necessidade de usar instanceof
fonte
Espero não estar perdendo nada óbvio aqui (também como sugerido pelo comentário de @Tristan Burnside ), mas por que não posso
SpecificItem.method()
ligaralso()
primeiro?Um fluxo-y maneira que eu posso pensar, à custa de talvez algum impacto no desempenho (YMMV), é a
collect()
viaCollectors.groupingBy()
na classe como a chave, em seguida, escolher o que você quer do resultadoMap
. Os valores são armazenados como aList
; portanto, se você esperava fazer essa filtragem em umSet
e espera filtrá-Set
lo, precisará de uma etapa adicional para inserir ainda mais os valores em um resultadoSet
.fonte
Aqui está a minha abordagem:
Nenhuma instância de , nenhuma conversão explícita (na verdade, é uma conversão explícita, mas mascarada por uma chamada de método). Eu acho que isso é o melhor possível.
fonte