Substituição por exemplo de Java?

10

Portanto, sou bastante novo em programação no mundo real (fora dos projetos acadêmicos) e encontrei muitas postagens dizendo que usar instanceofé uma coisa ruim para determinar a classe de um objeto específico.

Minha situação é que eu tenho três classes, uma classe de produto base, uma que se estende a isso e outra que se estende a isso. Todos eles são armazenados na mesma tabela em um banco de dados e eu tenho algum código que precisa usar os métodos em cada um para extrair dados deles.

Qual é a melhor prática para contornar essa maneira de fazê-lo? Eu li algumas coisas sobre polimorfismo, mas não consigo encontrar exemplos que resolvam o problema que tenho. Todos eles geralmente substituem um método que, para mim, não funciona, pois preciso extrair coisas diferentes dos diferentes objetos.

Existe uma maneira melhor de fazer isso ou estou preso a usar instanceofou algum tipo de reflexão para obter os campos específicos dos objetos?

Thomas Mitchell
fonte
10
Não é que a palavra instanceof- chave esteja errada; tentar encontrar a classe de um objeto geralmente é o problema. Nem sempre está errado, mas provavelmente no seu caso está. Talvez se você nos contar o que está tentando realizar, podemos sugerir uma solução usando o polimorfismo.
Andres F.
2
Ok, cada classe tem dados específicos. Eu quero extrair os dados específicos deles. Acho que percebi a resposta com a ajuda que tive. Algo como um método chamado getSpecifics()que é implementado de maneira diferente em cada um, com cada um retornando os dados específicos da classe?
Thomas Mitchell

Respostas:

16

O motivo instanceofé desencorajado é que não é OOP.

Não deve haver razão para o chamador / usuário de um objeto saber em qual classe concreta é uma instância e além de qual tipo a variável é declarada.

Se você precisar de um comportamento diferente nas subclasses, adicione um método e implemente-o de maneira diferente.

catraca arrepiante
fonte
11
Portanto, um método getSpecifics()(ou algo semelhante) em cada classe que retornará os detalhes para cada classe. Essa é a melhor abordagem?
Thomas Mitchell
@ Schmooo Você realmente precisa pensar sobre onde existe a funcionalidade comum na árvore de classes e quais contratos existem em cada nível.
3
Mas e um caso em que seu objeto cruza camadas e as informações de tipo são perdidas? Exemplo que eu crio a List. Eu passo para um objeto que aceita qualquer Iterable. Agora, esse segundo objeto passa-o para um terceiro objeto que usa um Listpara otimização ou um, Iterablemas é muito mais lento. O segundo não deveria saber que é uma lista, mas o terceiro gostaria muito de saber. O terceiro objeto não deve verificar, por exemplo, se é possível aplicar a otimização? Veja, por exemplo, goiaba FluentIterableque faz exatamente isso.
Laurent Bourgault-Roy
11
Eu diria que nem sempre é o caso de você adicionar o método à classe. Por exemplo, algum código obtém uma exceção e deve fazer algo com ele, dependendo do seu tipo. Digamos, faça um relatório ou faça algo para se recuperar de um erro. Esse tipo de funcionalidade definitivamente não se encaixa nas exceções. Ou, se as classes vierem de alguma biblioteca externa, você nem sequer tem os meios para modificar essas classes. Nesse caso, acho absolutamente válido confiar no instanceof.
Malcolm
9

instanceof não é necessariamente uma coisa ruim, no entanto, é algo que se deve olhar.

Um exemplo de onde funciona corretamente está em um local em que se obtém uma coleção do tipo base e você deseja apenas os de um subtipo. Obter os endereços de rede NetworkInterface.getNetworkInterfaces()retorna objetos NetworkInterface que possuem uma coleção de objetos InetAddress, alguns dos quais são Inet4Address e outros são Inet6Address. Se alguém quiser filtrar a coleção de objetos Inet4Address, é necessário usar instanceof.

Na situação que está sendo descrita na postagem original, há uma classe Base, algo que estende essa classe base e algo que estende a classe estendida. Embora não seja totalmente informativo, isso parece ter os fundamentos de um design menos que o ideal.

Quando você está retornando uma classe base, a menos que haja uma boa razão para ela ser projetada dessa maneira (compatibilidade com versões anteriores entre as especificações de uma versão anterior), você não deve tentar espiar os tipos subjacentes. Se você devolver um conjunto, sabe que está recebendo um conjunto. Isso permite que o desenvolvedor mude de ideia posteriormente para retornar um tipo mais específico (SortedSet) ou altere o tipo subjacente (HashSet para TreeSet) sem interromper nada.

Reconsidere seu design de como os objetos são estruturados e parentais para ver se é possível criar um modelo de classe melhor que não exija uma distinção de tipos.


fonte
É possível que a interface especifique um isOfType(SomeEnum.IPv4)método poderia ser uma maneira melhor de filtrar essas qualidades do que inspecionar o tipo de concreto via instanceof. E se você quiser dividir sua classe de implementação IPv4 posteriormente? Não que isso seja sempre melhor, mas é uma consideração.
Steven Schlansker
@StevenSchlansker Isso poderia funcionar para essa classe específica. Mas e se alguém precisasse inspecionar o tipo concreto para ver se uma conversão é possível (ou seria apenas lançada e capturar a exceção?) O Inet6Address implementa mais métodos que o InetAddress. Seria difícil trabalhar com interfaces (uma enumeração que enumera todas as classes do pacote? Ou carregador de classes?) E isso significaria que o método precisaria ser implementado manualmente (ou algum código de reflexão no Object). Considere como fazer (o instanceof Serializable) || (o instanceof Externalizable). instanceof é melhor que a alternativa
1

Você pode usar o método getClass ().

Tem certeza de que precisa de três classes diferentes? Talvez uma classe com um interruptor dentro sirva melhor?

Gangnus
fonte
7
getClasse instanceofcompartilhar desvantagens. O polimorfismo é melhor do que ambos quando se encaixa, e não vejo que não se encaixe no caso de uso do OP.
Não tenho nada contra a sua primeira frase. Mas o segundo - desculpe, eu não consigo entender o que você quer dizer.
Gangnus
11
Com getClassposso não ainda compartilham o mesmo problema que usar instanceof? Ainda terei que descobrir qual deles tenho e depois chamar um conjunto de funções. Idealmente, quero um método que retorne os dados específicos para essa classe sem precisar converter para esse objeto.
Thomas Mitchell
Estou reclamando que você ignorou o polimorfismo, pois geralmente é uma escolha melhor. Tenho certeza de que o caso de uso na pergunta pode ser feito com polimorfismo, portanto também não vejo a necessidade de usá-lo. (Além disso, resposta apenas reproduzir de outra pessoa não é bom.)
2
@ Gangus Eu não penso nisso como um "ataque", não quero ofender. Mas de qualquer forma. Não, a pergunta não é "o que mais pode ser usado", é "existe uma maneira melhor de fazer isso". A menos que você quer discutir getClassé a melhor maneira de fazê-lo, não tem negócio tendo a maior parte uma resposta ;-)
1

Normalmente, quando me vejo querendo saber o tipo de algo, isso significa que implementei minha estrutura de objetos incorretamente. Na maioria das vezes, isso se resume a violar o LSP .

No entanto, há momentos em que eu gostaria de ter uma maneira de enviar dinamicamente e economizar uma tonelada de código de chapa de caldeira e proteger minha estrutura de objetos à prova de futuro. O C # fornece a palavra-chave dinâmica nas parcelas mais recentes da estrutura, mas até onde eu sei, o Java ainda não possui algo parecido.

Dito isso, instanceof é geralmente melhor do que comparar classes, pois suportará a herança corretamente. Você também pode usar métodos como isAssignableFrom e outros da API de reflexão. Se você deseja implementar algo como despacho dinâmico, isso pode ser feito através da API de reflexão, mas cuidado, será lento. Use com cuidado; idealmente, você deve corrigir a estrutura do objeto e a criação do seu aplicativo, se puder.

Espero que isto ajude

Newtopian
fonte