Estaba leyendo sobre patrones de diseño, y leí que el patrón de diseño prototipo elimina la subclasificación excesiva.
¿Por qué es malo subclasificar? ¿Qué ventaja traería el uso de un prototipo sobre la subclase?
design-patterns
inheritance
David Faux
fuente
fuente
Respuestas:
¿Por qué es demasiado malo subclasificar?
"Demasiado" es un llamado al juicio; pero tómalo de mí, es malo. El código con el que trabajo tiene una herencia PROFUNDA y el código es muy difícil de leer, comprender, seguir, rastrear, depurar, etc. etc. Es efectivamente imposible escribir código de prueba para estas cosas.
El patrón prototipo elimina las subclases
¿O la pregunta significa "elimina demasiadas subclases?". Este patrón requiere la clonación de un objeto "plantilla" para evitar subclases, al menos en ese punto. No hay una regla que diga que la "plantilla" no puede ser una subclase.
Favorecer la composición sobre la herencia
Esta idea aquí también incluye delegación y agregación. Seguir esta heurística significa que su software tiende a ser más flexible, más fácil de mantener, ampliar y reutilizar.
Cuando una clase se compone de partes , puede sustituirlas en tiempo de ejecución . Esto tiene un profundo efecto en la capacidad de prueba.
La prueba es más fácil . Puede usar partes falsas (es decir, "simulacros", "dobles" y otras charlas de prueba). La herencia profunda de nuestro código significa que debemos instanciar toda la jerarquía para probar cualquier parte de ella. En nuestro caso, eso no es posible sin ejecutar el código en su entorno real. Por ejemplo, necesitamos una base de datos para crear instancias de objetos comerciales.
Los cambios vienen con efectos secundarios e incertidumbre : cuanto más "base" sea la clase, más extendidos serán los efectos, para bien o para mal. Puede haber cambios deseados que no se atreva a hacer debido a la incertidumbre de los efectos secundarios. O un cambio que es bueno para algún lugar en nuestra cadena de herencia es malo para otro. Esta es ciertamente mi experiencia.
fuente
Creo que una de las razones por las que esto se ha considerado una mala práctica es que, con el tiempo, cada subclase puede contener atributos y métodos que no tienen sentido para ese objeto a medida que avanza en la cadena (en una jerarquía poco desarrollada). Puede terminar con una clase hinchada que contiene elementos que no tienen sentido para esa clase.
Soy agnóstico sobre esto yo mismo. Parece dogmático decir que es malo. Cualquier cosa es mala cuando se usa mal.
fuente
Dos razones.
Es el rendimiento en tiempo de ejecución. Cada vez que invocas una subclase de una superclase, estás haciendo una llamada a un método, por lo que si has anidado cinco clases e invocas un método en la clase base, estarás haciendo cinco invocaciones de métodos. La mayoría de los compiladores / tiempos de ejecución tratarán de reconocer esto y optimizar las llamadas adicionales, pero solo es seguro hacerlo en casos muy simples.
Es la cordura de tus compañeros programadores. Si anidas cinco clases, tengo que examinar las cuatro clases para padres para establecer que realmente estás llamando a un método en la clase base, se vuelve tedioso. También es posible que tenga que pasar por cinco invocaciones de métodos cuando depure el programa.
fuente
"Demasiado" es un llamado al juicio.
Como con la mayoría de las cosas en programación, la subclasificación no es inherentemente mala cuando tiene sentido. Cuando el modelo de la solución de su problema tiene más sentido como una jerarquía que como una composición de partes, la subclasificación puede ser la opción preferida.
Dicho esto, favorecer la composición sobre la herencia es una buena regla general.
Cuando subclases, las pruebas pueden ser más difíciles (como señaló radarbob ). En una jerarquía profunda, aislar el código problemático es más difícil porque instanciar una subclase requiere traer toda la jerarquía de la superclase y un montón de código adicional. Con un enfoque de composición, puede aislar y probar cada componente de su objeto agregado con pruebas unitarias, objetos simulados, etc.
La subclasificación también puede hacer que exponga detalles de su implementación que quizás no desee. Esto dificulta el control del acceso a la representación subyacente de sus datos y lo vincula a una implementación particular de su modelo de respaldo.
Un ejemplo en el que puedo pensar es java.util.Properties, que hereda de Hashtable. La clase Propiedades solo está destinada a almacenar pares String-String (esto se observa en los Javadocs). Debido a la herencia, los métodos put y putAll de Hashtable se han expuesto a usuarios de Propiedades. Si bien la forma "correcta" de almacenar una propiedad es con setProperty (), no hay absolutamente nada que impida a un usuario llamar a put () y pasar una Cadena y un Objeto.
Básicamente, la semántica de las propiedades está mal definida debido a la herencia. Además, si alguna vez alguien quisiera cambiar el objeto de respaldo para Propiedades, el impacto tendrá un impacto mucho mayor en el código que usa Propiedades que si las Propiedades hubieran adoptado un enfoque más compositivo.
fuente
La herencia puede romper la encapsulación en algunos casos, y si eso sucede, es malo. Leer para más.
En los viejos tiempos sin herencia, una biblioteca publicaba una API y la aplicación que usa utiliza lo que es públicamente visible, y la biblioteca ahora tiene su propia forma de manejar los engranajes internos que siguen cambiando sin romper la aplicación.
A medida que evolucionan las necesidades, la biblioteca puede evolucionar y puede tener más clientes; o puede proporcionar una funcionalidad extendida heredando de su propia clase con otros sabores. Hasta ahora tan bueno.
Sin embargo, lo fundamental es que si una aplicación toma la clase y comienza a subclasificarla, ahora una subclase es en realidad un cliente en lugar de un socio interno. Sin embargo, a diferencia de una forma clara e inequívoca de que se define la API pública, la subclase ahora es mucho más profunda dentro de la biblioteca (acceso a todas las variables privadas, etc.). Todavía no está mal, pero un personaje desagradable puede conectar una API que está demasiado dentro de la aplicación, así como en la biblioteca.
En esencia, aunque este no siempre sea el caso, pero,
Permitir subclases puede ser incorrecto si ese punto.
fuente
Respuesta rápida corta:
Depende de lo que estés haciendo.
Respuesta aburrida extendida:
Un desarrollador puede hacer una aplicación. usando cualquiera de las subclases o plantillas (prototipo). A veces una técnica funciona mejor. A veces, la otra techinque funciona mejor.
Elegir con la técnica funciona mejor, también requiere, considerar si un escenario de "herencia múltiple" está presente. Incluso si el lenguaje de programación solo admite herencia única, plantillas o prototipos.
Nota complementaria:
Algunas respuestas se relacionan con la "herencia múltiple". Pensamiento, no es la pregunta principal, está relacionado con el tema. Hay varias publicaciones similares sobre "herencia múltiple versus composición". Tuve un caso donde mezclo ambos.
fuente