Tengo varias clases Parent
y Child1
... Child9
implementado en Java. Parent
es una clase abstracta, que contiene todas las variables comunes de las clases secundarias (muchas, que es la razón principal por la que hice Parent
una clase abstracta y no una interfaz), algunos métodos abstractos y algunos implementados.
Algunas de las clases secundarias tienen métodos personalizados que son específicos para ellos. Muy a menudo me encuentro llamando a un método hijo usando downcasting:
Parent p = new Child1();
((Child1) p).child1SpecificMethod();
De alguna manera tengo la sensación de que esta es una mala práctica de OOD, pero no estoy muy seguro de si ese es realmente el caso, respectivamente, de cómo mejorar el diseño.
- Editar: lo que probablemente debería cambiar de todos modos es el hecho de que uso la clase Parent para organizar muchas (por ahora) variables comunes, haciéndolas (o un objeto contenedor) miembros de las clases concretas.
p
como unParent
en primer lugar? Cumplir con los tipos generales es una buena práctica para las API y los tipos de retorno, pero no dentro del mismo ámbito en el que usted asigna una clase concreta.Respuestas:
Esto no es solo una mala práctica , es innecesariamente complicado.
¿Por qué usas la herencia en general?
Cuando usa la herencia, tiene un conjunto de comportamientos comunes, que desea poner a disposición de muchos operadores diferentes. Esto incluye la herencia de clases y también la herencia de la interfaz . El heredero , por así decirlo, es a menudo una especialización de la clase de la que hereda; lo cual es principalmente cierto para la herencia de clase.
Piense en un auto de clase y un porche de subclase (lo típico es una relación ). Tiene un comportamiento general como arrancar / parar el motor , la dirección , etc. Si trata a un Porsche como un automóvil, está obligado a este aspecto de su comportamiento. Si sabe que solo quiere un Porsche y solo lo trata como un Porsche , es redundante instanciar un Porsche como un automóvil y obtener el comportamiento de Porsche a través del casting .
El polimorfismo tiene sentido al revés:
Tiene un porsche y necesita tratarlo desde el aspecto de un automóvil; por ejemplo, conducir
Siempre y cuando su Porsche acepte girar a la izquierda , girar a la derecha , subir , bajar , etc., puede utilizar el polimorfismo / sustitución uno por otro.
Es mejor instanciar sus objetos en su forma especializada. Entonces podría aprovechar al máximo el polimorfismo y usarlo solo cuando lo necesite .
Dicho eso:
Parent p = new Child1();
no tiene sentido para mí.Editar: implementaría porsche diferente (a través de la composición ), pero por el bien del ejemplo, es un automóvil.
fuente
Su sentimiento es correcto al considerarlo una mala práctica. Imagine su código de ejemplo un poco diferente:
¿Cómo sabes que el valor de p es realmente Child1? No lo hace y esto puede causar una ClassCastException en tiempo de ejecución. Si necesita llamar a child1SpecificMethod () en su código, debe asegurarse de que p sea del tipo Child1. Si eso no es posible porque el Objeto p se pasa a su código (por ejemplo, como un parámetro de método) como tipo Parent, podría considerar usar una variante del Visitor-Pattern y ejecutar child1SpecificMethod en el handle-Method de su objeto visitante, que maneja Niño1.
fuente
Utilice la búsqueda de capacidades en su lugar. No dé acceso a las clases secundarias, considérelas implementaciones de la clase primaria
Luego defina interfaces especificando alguna capacidad , característica.
Uso:
Este mecanismo de descubrimiento es muy flexible. Usar delegación en lugar de herencia puede ser bastante gratificante. Tenga en cuenta que ya no es necesario tener clases secundarias.
O en Java 8 (donde son posibles varias variaciones, y la interfaz también podría ser funcional):
Haga en la clase Parent una búsqueda de alguna capacidad:
O en Java 8:
La clase infantil:
O más dinámico:
fuente
Agregue un método abstracto child1SpecificMethod () en la clase Parent (debe marcar la clase como abstract) y proporcione su implementación en la clase secundaria respectiva.
fuente