java - observer - design patterns singleton
Favorecer la composiciĆ³n sobre la herencia (7)
Esta pregunta ya tiene una respuesta aquí:
- ¿Prefiere la composición sobre la herencia? 33 respuestas
Favorecer la composición sobre la herencia
es una frase muy popular. Leí varios artículos y al final cada artículo dice
usar herencia cuando existe una relación IS-A pura entre las clases.
Un ejemplo de este artículo :
Aquí, entre Apple y Fruit, existe una clara relación IS-A, es decir, Apple IS-A Fruit, pero el autor también ha demostrado que Apple HAS-A Fruit (composición) muestra la trampa cuando se implementa con herencia.
Me confundí un poco aquí que cuál es el significado del enunciado
usar herencia cuando existe una relación IS-A pura entre las clases.
¿El uso de la composición sobre la herencia significa que siempre se intenta aplicar la composición incluso si existe una relación IS-A pura y se deja la herencia solo para aquellos casos en los que la composición no tiene sentido ?
Además, me gustaría añadir que el patrón Decorator es un ejemplo en el que puedes usar la composición sobre la herencia y agregar responsabilidades a los objetos dinámicamente. El ejemplo del patrón Decorator se menciona en Java efectivo en el elemento "Favorecer composición sobre herencia". Para tomar un ejemplo de la API de Java; BufferedReader decora un Reader (en lugar de extender FileReader, PipedReader, FilterReader, etc.) y, por lo tanto, tiene la capacidad de decorar cualquier tipo de Reader. La funcionalidad de almacenamiento en búfer se adjunta a estos lectores en tiempo de ejecución, que es el patrón Decorator.
Aquí la extensión por subclases sería poco práctica.
Creo que este es uno de los puntos más discutidos en el diseño orientado a objetos. Como se sugiere en el artículo, la composición siempre es preferible a la herencia. Eso no significa que nunca deberías usar la herencia. Deberías hacerlo donde tenga más sentido (lo que puede ser discutible).
Hay muchas ventajas de usar composición, algunas de ellas son:
- Tendrás control total de tus implementaciones. es decir, puedes exponer solo los métodos que pretendes exponer.
- cualquier cambio en la súper clase se puede proteger modificando solo en su clase. Las clases de clientes que usan sus clases, no necesitan hacer modificaciones.
- Le permite controlar cuándo desea cargar la superclase (carga diferida)
Creo que una buena pauta sería:
Cuando hay una relación IS-A, usa herencia. De lo contrario, usa la composición.
La razón de esto está relacionada con otro concepto en Diseño orientado a objetos: polimorfismo. El polimorfismo es una característica de muchos lenguajes OOP donde un objeto se puede usar en lugar de otro objeto, siempre que la clase del primero sea una subclase del segundo.
Para ilustrar, imagine si tiene una función que incluya un tipo de animal. Cuando usas herencia, solo tienes una función:
void feed( Animal a );
El polimorfismo nos asegura que cualquier subclase de animal que incorporemos será aceptada. De lo contrario, nos veremos obligados a escribir una función para cada tipo. Creo que los beneficios de esto superan sus desventajas (por ejemplo, la reducción de la encapsulación).
Si no hay una relación IS-A, creo que el polimorfismo no será muy efectivo. Por lo tanto, sería mejor utilizar la composición y tener un encapsulado / aislamiento mejorado entre las clases.
Cuando utiliza la herencia para reutilizar el código de la superclase, en lugar de anular los métodos y definir otro comportamiento polimórfico, a menudo es una indicación de que debe usar composición en lugar de herencia.
La clase java.util.Properties
es un buen ejemplo de un mal uso de la herencia. En lugar de usar un Hashtable para almacenar sus propiedades, amplía Hashtable, para reutilizar sus métodos y evitar volver a implementar algunos de ellos usando la delegación.
En el artículo, no hay tal frase:
use inheritance when there is pure IS-A relationship between classes
Además, Google no lo encontró en ningún otro lugar, excepto su publicación.
En cambio, el artículo dice:
Make sure inheritance models the is-a relationship. My main guiding philosophy is that inheritance should be used only when a subclass is-a superclass. In the example above, an Apple likely is-a Fruit, so I would be inclined to use inheritance.
Esto significa que, si hay una relación IS_A, intente usar primero la herencia y no la composición. Y no hay preferencia de using composition over inheritance
, cada uno es bueno para su propio rol.
Usa herencia cuando la relación es permanente. No use la extensión solo para obtener un comportamiento libre. Esto es a lo que se refieren en el ejemplo IS-A. Extienda solo si la clase que se extiende realmente es una extensión del padre. Habrá momentos en los que no se cortará y se secará, pero en general. La composición proporciona flexibilidad en el futuro también si necesita extenderse desde la clase "correcta".
Este es un artículo antiguo pero excelente sobre extends:
http://www.javaworld.com/javaworld/jw-08-2003/jw-0801-toolbox.html
Yo diría que no. En el escenario fruta / manzana, tiene sentido usar herencia. El autor del artículo confirma eso también: "En el ejemplo anterior, una manzana probablemente es una fruta, por lo que me inclinaría a usar la herencia".
Si su subclase es claramente una superclase, la herencia está bien. En la práctica, sin embargo, encontrarás muchas más situaciones que se resuelven mejor usando la composición.