Tal vez haya notado que la gente lo ha dicho en los últimos meses, pero los programadores lo han sabido durante mucho más tiempo. Ciertamente lo he estado diciendo donde sea apropiado durante aproximadamente una década.
El punto del concepto es que hay una gran sobrecarga conceptual en la herencia. Cuando está utilizando la herencia, entonces cada llamada a un solo método tiene un envío implícito. Si tiene árboles de herencia profunda, o envío múltiple, o (aún peor) ambos, entonces averiguar dónde se enviará el método en particular en cualquier llamada particular puede convertirse en un PITA real. Hace que el razonamiento correcto sobre el código sea más complejo y hace que la depuración sea más difícil.
Déjame dar un ejemplo simple para ilustrar. Supongamos que en lo profundo de un árbol de herencia, alguien llamó a un método foo
. Luego aparece alguien más y agrega foo
en la parte superior del árbol, pero haciendo algo diferente. (Este caso es más común con herencia múltiple). Ahora, esa persona que trabaja en la clase raíz ha roto la oscura clase infantil y probablemente no se da cuenta. Podría tener una cobertura del 100% con las pruebas unitarias y no notar esta ruptura porque la persona en la parte superior no pensaría en probar la clase infantil, y las pruebas para la clase infantil no piensan en probar los nuevos métodos creados en la parte superior . (Es cierto que hay formas de escribir pruebas unitarias que detectarán esto, pero también hay casos en los que no se pueden escribir fácilmente las pruebas de esa manera).
Por el contrario, cuando usa la composición, en cada llamada generalmente queda más claro a qué está enviando la llamada. (De acuerdo, si está utilizando la inversión de control, por ejemplo, con la inyección de dependencia, entonces averiguar a dónde va la llamada también puede ser problemático. Pero generalmente es más fácil de descifrar). Esto hace que el razonamiento sea más fácil. Como beneficio adicional, la composición resulta en tener métodos separados entre sí. El ejemplo anterior no debería ocurrir allí porque la clase secundaria se movería a algún componente oscuro, y nunca hay dudas sobre si la llamada a foo
estaba destinada al componente oscuro o al objeto principal.
Ahora tiene toda la razón, ya que la herencia y la composición son dos herramientas muy diferentes que sirven a dos tipos diferentes de cosas. La herencia segura conlleva una sobrecarga conceptual, pero cuando es la herramienta adecuada para el trabajo, conlleva menos sobrecarga conceptual que tratar de no usarla y hacer a mano lo que hace por usted. Nadie que sepa lo que están haciendo diría que nunca debes usar la herencia. Pero asegúrate de que sea lo correcto.
Desafortunadamente, muchos desarrolladores aprenden sobre el software orientado a objetos, aprenden sobre la herencia y luego salen a usar su nuevo hacha con la mayor frecuencia posible. Lo que significa que intentan usar la herencia donde la composición era la herramienta correcta. Es de esperar que aprendan mejor a tiempo, pero con frecuencia esto no ocurre hasta después de algunas extremidades extraídas, etc. Decirles desde el principio que es una mala idea tiende a acelerar el proceso de aprendizaje y reducir las lesiones.