Tenho várias classes Parent
e Child1
... Child9
implementado em Java. Parent
é uma classe abstrata, contendo todas as variáveis comuns das classes filho (muito, que é a principal razão pela qual eu criei Parent
uma classe abstrata e não uma interface), alguns métodos abstratos e alguns implementados.
Algumas das classes filho têm métodos personalizados que são específicos para eles. Muitas vezes, me pego chamando um método filho usando downcasting:
Parent p = new Child1();
((Child1) p).child1SpecificMethod();
De alguma forma, tenho a sensação de que essa é uma prática ruim de OOD, mas não tenho certeza se esse é realmente o caso, respectivamente, de como melhorar o design.
- Editar - O que eu provavelmente deveria mudar de qualquer maneira é o fato de usar a classe Parent para organizar muitas (por enquanto) variáveis comuns, tornando-as (ou um objeto de contêiner) membros das classes concretas.
p
como umParent
em primeiro lugar? A adesão a tipos gerais é uma boa prática para APIs e tipos de retorno, mas não dentro do mesmo escopo em que você aloca uma classe concreta.Respostas:
Isso não é apenas má prática , é desnecessário e complicado.
Por que você usa herança em geral?
Ao usar a herança, você tem um conjunto comum de comportamentos, que deseja disponibilizar para muitas operadoras diferentes. Isso inclui herança de classe e também herança de interface . O herdeiro , por assim dizer, é muitas vezes uma especialização da classe da qual herdou; o que é verdade principalmente para a herança de classe.
Pense em um carro de classe e uma porsche de subclasse (o típico é um relacionamento). Você tem um comportamento geral, como ligar / desligar o motor , direção e assim por diante. Se você trata uma Porsche como um carro, está vinculado a esse aspecto de seu comportamento. Se você sabe que só quer uma porsche e lida com ela como uma porsche , é redundante instanciar uma porsche como um carro e obter um comportamento da porsche através da transmissão .
O polimorfismo faz sentido ao contrário:
Você tem uma porsche e precisa tratá-la do aspecto de um carro; por exemplo, dirigir
Desde que a sua Porsche aceite direção à esquerda , direção à direita , mudança para cima , mudança para baixo , etc., você poderá usar o polimorfismo / substituição um pelo outro.
É melhor instanciar seus objetos em sua forma especializada. Então você pode aproveitar ao máximo o polimorfismo e usá-lo somente quando precisar .
Dito isto:
Parent p = new Child1();
não faz sentido para mim.Edit: Eu implementaria o Porsche diferente (via composição ), mas pelo bem do exemplo, é um carro.
fonte
Seu sentimento está certo ao considerá-lo uma má prática. Imagine seu código de exemplo um pouco diferente:
Como você sabe que o valor de p é realmente Child1? Você não faz isso e isso pode causar uma ClassCastException em tempo de execução. Se você precisar chamar child1SpecificMethod () no seu código, verifique se p é do tipo Child1. Se isso não for possível porque o Objeto p é passado para o seu código (por exemplo, como um parâmetro do método) como o tipo Parent, você pode considerar o uso de uma variante do Visitor-Pattern e executar child1SpecificMethod no handle-Method do objeto do visitante, que manipula Criança1.
fonte
Use a pesquisa de recursos. Não dê acesso às classes filho, considere-as implementações da classe Pai.
Em seguida, defina interfaces especificando alguma capacidade , recurso.
Uso:
Esse mecanismo de descoberta é muito flexível. Usar delegação em vez de herança pode ser bastante gratificante. Observe que não é mais necessário ter aulas filhas.
Ou no java 8 (onde várias variações são possíveis e a interface também pode ser funcional):
Faça na classe Parent uma pesquisa por algum recurso:
Ou no java 8:
A classe filho:
Ou mais dinâmico:
fonte
Adicione um método abstrato child1SpecificMethod () na classe Parent (você precisa marcar a classe como abstrata) e forneça sua implementação na respectiva classe filho.
fonte