Herencia vs Composición ¿Tienes claro cuál es el rival más débil?
Sergio Martinez Rodríguez

Hola de nuevo de nuevo a todos, esta vez ando por aquí para contar un tema más que interesante y del que seguro todos hemos escuchado hablar mucho: “herencia”. Sí amigos, vamos a hablar de la más que castigada herencia en programación orientada a objetos. Vamos a ver si realmente es tan malo usarla como dicen y por qué, y vamos a ver por qué solemos escuchar eso de favorecer la composición en lugar de la herencia.

El post está dividido en tres partes, primero una explicación de la herencia, luego una explicación de la composición y por último una comparación de ambas. ¡Así que vamos al trapo que no hay más tiempo que perder!

Herencia

Empecemos con la definición: Herencia es cuando un objeto o clase se basa en otro objeto o clase, usando la misma implementación o comportamiento. Esto es un mecanismo para la reutilización de código para permitirnos extensiones independientes del software original mediante clases públicas e interfaces.

Bien, no te preocupes si te suena un poco a chino, lo entenderás con el desarrollo que vamos a ir haciendo. Pero permíteme pedirte que recuerdes eso de extensiones independientes.

Para simplificar esta definición y ajustar al máximo lo que debe ser la herencia vamos a hacer un ejercicio de abstracción y vamos a decir que la herencia tiene cabida donde existe una relación “es un/una”. ¡Cuidado!, esta relación es unidireccional hacia la clase padre. Pongamos un ejemplo para verlo mejor:

Esquema de herencia

La bicicleta simple arriba sería la super clase, y los tipos concretos abajo, diríamos que son las subclases. Es decir el supertipo o abstracción es la superclase de los subtipos o concreciones. Además decimos que una bicicleta de carretera es siempre una bicicleta, pero sin embargo, una bicicleta no tiene por qué ser siempre de carretera, puede ser de cualquier otro tipo concreto. Esto quiere decir que es unidireccional, el hijo es un tipo concreto de lo que es el padre.

En el 95% de los casos que usas herencia, si no te planteas las preguntas correctas la vas a usar mal Clic para tuitear

Polimorfismo

Esto nos otorga también una propiedad que se llama polimorfismo, que quiere decir que cualquiera de las formas hijas pueden adoptar la forma padre, o lo que es lo mismo, el padre puede estar enmascarando a cualquier hijo mediante su forma.

Una de las principales potencias de la herencia es el polimorfismo que nos permite abstraernos del objeto concreto que usamos y trabajar con los supertipos.

La relación de “ser” vs “tener”

La connotación de la relación “es un” es más fuerte de lo que creemos, porque ha de ser de por vida, ¿qué quiere decir esto? lo vemos mejor con un ejemplo:

A ti te encanta correr, y podríamos decir que “eres un runner”, pero claro, es posible que cuando tengas 10 nietos y 80 años prefieras dedicar tu tiempo a la fotografía por ejemplo y dejes de ser un runner. Pues ahí tienes una falsa relación “es un”.

Hubiera sido un error plantear la clase que representa tu persona como herencia de runner porque tú no eres un runner de por vida (lo siento por mucho que queramos, y eso que a mi también me gusta correr). Simplemente en ese momento de tu vida tenías un Rol. Y te pido que de nuevo recuerdes, esta vez, el verbo “Tener”.

¿Por qué tanto énfasis en el significado de “ser o no ser” en la herencia? porque realmente es necesario tener en cuenta esto y la herencia no hubiera cogido tanta mala fama si antes de usarla todos nos hubiéramos planteado esa pregunta de la forma que arriba os comento.

Ventajas de la herencia

La mala fama de la herencia no es por que sea mala per se, es porque en el 95% de los casos que vas a usar herencia, si no te planteas las preguntas correctas la vas a usar mal. Porque la herencia engatusa. Sí sí, te seduce con sus beneficios, es el lado oscuro, y tiene todas estas ventajas:

  • La herencia es atractiva porque permite reutilizar código de una manera rápida, sencilla y evidente.
  • La herencia es poderosa porque me permite jugar con el polimorfismo con facilidad.
  • La herencia me permite sobrescribir métodos, así que si algo no es exactamente como espero siempre puedo cambiarlo si fuera necesario, por lo que es versátil.
  • La herencia usando algo parecido al patrón de diseño Template Method me permite crear clases abstractas que hacen que al heredar de ellas me quede un desarrollo guiado por la plantilla creada, ahorrando así tiempo y quedando un desarrollo guiado muy sencillo.

Son un montón de ventajas que nos empujan a usar herencia en nuestros primeros razonamientos y además son, en cierto modo, verdad. Pero en algún momento se volverán contra ti, con todas sus fuerzas.

¡Alerta! Cuándo la herencia se vuelve en tu contra

La experiencia en muchos proyectos, y de muchos desarrolladores, lo ha demostrado. Hay más razones que te pueden llevar a usar herencia en un primer momento, pero estas son las que primero se nos vienen a la cabeza. Vamos a ver por qué se vuelven contra nosotros estos “caramelitos”.

La principal razón es bastante obvia aunque no lo parezca. En un proyecto que se enmarca en un proceso de desarrollo ágil, donde los requisitos cambian constantemente y no están para nada bajo control, es imposible hacer suposiciones del tipo: “esta pantalla va a tener que realizar siempre esta acción”, “esta respuesta de servidor siempre tiene 4 listados”. Borra de tu mente la palabra siempre, siempre guía de forma equivocada en nuestra mente a “es un” y eso guía a herencia.

En un desarrollo donde todo cambia, la herencia puede dejar de cumplirse en cualquier momento. Clic para tuitear

Por lo tanto en etapas iniciales del proyecto, que es donde precisamente más incertidumbre tenemos, es prácticamente imposible intentar modelar comportamiento basado en pautas que podamos considerar constantes, porque nos guste o no, todo está sujeto a cambio.

Por ese motivo, si empezamos a usar comportamientos heredados, aunque podamos a priori obtener resultados rápidos y robustos, en algún momento empezarán a sucederse cosas que yo categorizo con nombres como estos: “la fiesta de los override”, “el aluvión de métodos heredados inservibles”, “la herencia de 7 niveles”, “el quiero heredar y no puedo porque estoy sujeto a otra herencia” y un montón de inconvenientes muy muy divertidos que van a ensuciar nuestro código con el cambio, y el cambio es cuestión de tiempo.

Pues bien, el problema de los problemas, es mal usar la herencia, es decir, utilizar herencia en el lugar y momento inadecuados. De hecho hacer eso es lo más parecido que hay a hipotecar tu software: al principio todo es muy bonito y todo funciona, pero cuando empieces a pagar intereses… ¡Ay! pobre de ti.

Usar mal la herencia es lo más parecido que existe a hipotecar tu software Clic para tuitear

Pero gracias a la evolución de la ingeniería del software y después de darnos muchas veces de bruces con la herencia, nos hemos dado cuenta de que existe otro camino.

Composición

La definición viene a decir algo así: Composición quiere decir que tenemos una instancia de una clase que contiene instancias de otras clases que implementan las funciones deseadas.

Es decir, estamos delegando las tareas que nos mandan a hacer a aquella pieza de código que sabe hacerlas. El código que ejecuta esa tarea concreta está sólo en esa pieza y todos delegan el ella para ejecutar dicha tarea. Por lo tanto estamos reutilizando código de nuevo.

Vamos a ver un esquema como en el caso anterior:

Esquema de composión

En este caso decimos que el coche esta compuesto por ruedas, volante, cinturones de seguridad, luna… es decir, el coche tiene elementos o usa elementos para hacer todas las funciones que puede realizar. Delega sus responsabilidades en colaboradores designados para cada responsabilidad.

En la composición, delegamos responsabilidades en colaboradores designados para ello Clic para tuitear

¿Te acuerdas de “tiene” en el contexto del rol del runner? Tenías el rol de runner, es decir, era una cualidad de tu persona en ese momento. Lo que aplica en ese caso por lo tanto es la composición también.

En este caso, el coche como tal no está atado a nada que le diga que tiene que usar unos neumáticos concretos en sus ruedas como podía pasar en la herencia por ejemplo. Las ruedas de hecho son una pieza modular e intercambiable que tiene interacción con el coche por medio de una interfaz. Pero las ruedas saben como ser rueda y qué neumático les viene bien. Es su labor.

Esta forma de diseñar nuestro software nos permite que el resultado sea un sistema mucho más flexible en tiempo de programación e incluso en tiempo de ejecución.

Comparativa

Todo parecen ventajas con la composición, ¿no? Bueno no es tan fácil, algo malo ha de tener… Vamos a ver una tabla que hace una comparativa.

Como podemos ver, un diseño basado en composición requiere mucho más tiempo. Es un software más mimado, más pensado, que requiere de un número mayor de clases que hacen cosas más concretas

¿Te acuerdas del principio de responsabilidad única? Pues eso es, muchas piezas interactuando entre sí, donde cada una tiene una y sólo una tarea que es su razón de existir.

Comparación Herencia vs Composición

Por seguir marcando diferencias entre la herencia y la composición, cabe destacar que la herencia se relaciona en una forma 1:1. Esto evidentemente es provocado por la relación “es un”, donde un subtipo “contiene” un y sólo un subtipo, entre comillas porque no lo contiene realmente, es él mismo “per se” es padre e hijo al mismo tiempo.

Sin embargo, haciendo uso de composición podemos elegir si vamos a tener 0, 1 o N elementos con los que interactuar del mismo tipo. Esto es muy versátil en tiempo de ejecución incluso, ya que podemos hacer que un objeto que tenía un rol deje de tenerlo, por ejemplo.

Esto hace que a su vez en la composición entre en juego la creación/destrucción de elementos dentro del objeto compuesto. Esto no existe por ejemplo en herencia ya que el objeto ya tiene lo que viene dado y lo que pueda implementar por extensión.

Usando polimorfismo en la composición

Y aquí viene lo peor de la composición, pero no te asustes, podemos solucionarlo. La composición por si misma no es polimórfica. Esto era de esperar, pero hay una solución muy potente a esto: ¿Qué pasa si hacemos que nuestros objetos compuestos implementen las interfaces que nosotros queramos?

¡Efectivamente! Con el uso de interfaces, podemos hacer que nuestros objetos compuestos se hagan pasar por la forma que nos venga bien. Y lo que es mejor, puedes implementar varias interfaces en cualquier momento o dejar de implementarlas con muchas más versatilidad que en la herencia, sin estar atado a nada más que los métodos que implemente esa interfaz concreta.

Con el uso de interfaces conseguimos traer el polimorfismo al mundo de la composición Clic para tuitear

Veamos un ejemplo:

Polimorfismo en la composición

Como puedes ver MainActivity, que puede ser una pantalla cualquiera en Android, tiene una funcionalidad que le viene dada por medio de un elemento que contiene y no por heredar de nada, y la forma que tiene de decir al resto del mundo que sabe navegar es usando la interfaz NavigationInterface.

Si dejara de tener esa cualidad, no tendría más que dejar de implementar la interfaz y no hacer uso del objeto o eliminarlo. Si esto fuera herencia, y tuviéramos dos niveles de herencia ¿que pasaría si ya no quiero o necesito tener la funcionalidad del primer nivel pero necesito la del segundo? Como puedes ver, el segundo nivel de herencia esta fuertemente acoplado al primero y no podemos tener el segundo sin el primero.

Además ¿que hubiera pasado su cambiamos primer y segundo nivel para nuestras necesidades y más clases dependen de ellos? Todo eso provocaría fallos, efectos de lado.

Sin embargo, en este caso, al igual que tenemos la funcionalidad de navegación, podríamos asignar y eliminar otras siguiendo la misma estrategia sin que otras clases se puedan ver afectadas por el cambio.

Cambiando el comportamiento en tiempo de ejecución

Voy más allá: imagina que el NavigationDelegate no es una implementación concreta sino que es una interfaz a su vez. Esto nos permitiría usar un patrón Strategy para que pudriéramos cambiar incluso en tiempo de ejecución la navegación concreta que queremos en cada momento.

Quizás nos interese en un momento bloquear el evento de back, y hay una implementación de la interfaz NavigationDelegate que asignamos según nos convenga a nuestro objeto compuesto. Maravilloso ¿no crees?.

Para que no haya pie a la confusión, hemos hablado de dos interfaces:

  • La primera otorga el polimorfismo a nuestro objeto compuesto que se perdía al usar composición, y a su vez sirve como “una declaración de cualidades” que puede tener nuestro objeto compuesto, es decir, define aquello de lo que es capaz de hacer.
  • La segunda otorga a nuestro objeto compuesto la flexibilidad de poder cambiar quién va a implementar la tarea concreta en cualquier momento.

Cuando la herencia tiene sentido

Bueno, si sigues empeñado en usar herencia en ciertos casos, ¡vamos a ver en qué casos tiene cabida!

  • Si tenemos dos clases directamente relacionadas que están basadas una en la otra y pertenecen al mismo dominio lógico, y estás seguro de que no van a cruzar fronteras no deseadas (por ejemplo ni ellas ni ninguna extensión saldrá del paquete), puedes optar por una relación de herencia.
  • Si la subclase es y será siempre algo basado en la superclase y además la implementación de la superclase es apropiada e incluso necesaria para la subclase , puedes aplicar herencia sin miedo a equivocarte.
  • Si además de lo que acabas de leer, la subclase es candidata a sólo añadir nueva funcionalidad y no a sobrescribir nada, sigues por el buen camino y la herencia es bienvenida.

Todo aquello que vaya en contra de uno de estos consejos debe hacerte dudar de aplicar herencia.

Modelado de Dominio

Si te das cuenta, todas las premisas se suelen cumplir en un marco bastante común: objetos de negocio, entidades, value objects y otros objetos de este tipo son susceptibles de poder ser modelados con relaciones de herencia.

Aún así te recomiendo que pienses bien tus relaciones de herencia. Por cierto, no viene mal recordar qué es la lógica de dominio de vez en cuando, echa un vistazo a los artículos sobre Domain Driven Design.

Desarrollo de Frameworks

Otro caso susceptible de modelar mediante el uso de herencia puede ser el desarrollo del frameworks, SDKs, aunque este tiene sus defensores y detractores. Aún modelando relaciones basadas en herencia, no podemos abusar de ello.

El framework de Android es un claro ejemplo del abuso de relaciones de herencia. Ahora me estoy dedicando al desarrollo de un SDK y en mi opinión me gusta más dejar la libertad que da la composición a atar al cliente de tu framework a una relación de herencia.

Pero esto como he dicho, aún siendo un campo susceptible de modelarse con herencia en un primer momento, da pie a un largo debate, porque siguen estando presentes muchos de los inconvenientes ya estudiados.

Casos de mal uso de la herencia

Una vez vistos los casos en los cuales podría tener la herencia cabida, vamos a ver algo que es más interesante si cabe: ejemplos de algunos casos comunes en los cuales nos empeñamos en meter herencia por alguna extraña razón, y ésta no tiene cabida:

Modelar comportamiento del sistema como si fueran objetos de modelo que representan estado

Por ejemplo: un caso de uso modela comportamiento, y no estado, y no tenemos por qué heredar de un caso de uso base que tenga métodos que supuestamente vayan a usar todos los casos de uso, porque es muy probable que eso no sea así.

Esto es un error muy común que se repite con al inicio de muchos diseños de software. Tomamos decisiones demasiado complejas y de muy bajo nivel en etapas tempranas del proyecto.

Ejemplo claro:

No puedo hacer una clase BaseRequest con un método getJSON() que escriba mi objeto con formato JSON. Con eso estoy suponiendo que todos mis Request van a ser JSON, y si en algún momento he de usar un multipart con formato [formulario + imagen], la consistencia de mi sistema estaría comprometida porque no puede heredar de esa request, y me vería obligado a crear otro tipo request.

Estoy tomando una decisión al principio del proyecto que no está para nada clara y está atando mi desarrollo a tomar un camino que no se si es el que debo seguir. Por lo tanto estoy saliéndome de la flexibilidad que me otorgara en ese caso un objeto compuesto, el cual me da la oportunidad de retrasar las decisiones de un grano tan fino hasta el último momento.

Imaginemos que forzosamente tenemos que tomar una decisión de ese tipo por algún motivo, siguiendo el camino de la composición, tendremos la gran ventaja de que los cambios estarán acotados y bajo control, al menos mucho más que con la herencia, con lo cual cualquier decisión equivocada y su posterior rediseño van a ocasionar unos efectos de lado que implicarán cambios en muchas menos piezas de código.

Diseños Template Method

De igual modo pasa con los diseños en plan Template Method. Es muy común crear ciclos de vida totalmente innecesarios mediante una herencia mal aplicada, que en un principio pensamos que nos van a facilitar el desarrollo, pero que acaba convirtiendo cualquier modificación en pesadilla…

¿Es realmente necesario crear un flujo de ejecución o ciclo de vida a los elementos? en la mayor parte de los casos no. Y si lo fuera, ¿es realmente la herencia la solución?

Ten en cuenta lo siguiente: abstraer comportamiento de piezas del sistema en etapas tempranas del diseño es una de las tareas más complejas de la ingeniería del software, y crear una relación de herencia no es más que crear una abstracción de algo que siempre va a ser de ese modo. ¿En serio te merece la pena arriesgar tanto?

Abstraer comportamiento en etapas tempranas del diseño es una de las tareas más complejas Clic para tuitear

La respuesta probablemente sea no. Pero si aún así te equivocas, como todos nos equivocamos, y acabas en el “berenjenal”de la herencia, presta atención a los siguientes puntos porque te pueden hacer detectar cuanto antes que la herencia se ha aplicado de mala manera.

Cómo detectar que estás usando mal la herencia

  • Cuando los Overrides empiezan a crecer y multiplicarse por tu código de forma exponencial y a veces de forma obligada y sin mucho sentido… ¡Algo huele mal!
  • Si la relación “Es un” se ha roto por algún motivo… ¡Mal asunto!
  • Si tu código, cuando crece por extensión, requiere modificaciones de clases que son supertipos, y además siempre suelen ser las mismas clases base las que estas tocando… ¡Mal royo!
  • Si los niveles de herencia empiezan a ser muchos, te pierdes al tirar del hilo y los efectos de lado empiezan a manifestarse… ¡Se te está pasando el arroz!

Así que si en algún momento sospechas de alguno de estos puntos, echa un ojo de cerca a ese código. Y si se vuelve a manifestar de alguna forma parecida, dale caña al rediseño de esa parte, porque cuanto antes pongas medidas y cortes de raíz, más fácil te resultará. Y recuerda esta vez ir por la vía de la composición.

Conclusión

Y no me queda mucho más que añadir una conclusión que no deja de ser una opinión personal y que he dicho ya por algún lado. ¡¡La herencia, no es mala!! de hecho puede ser la solución que necesitas en un momento concreto.

El problema es que es muy malo es aplicar mal herencia. Y como en la mayor parte de los sistemas que desarrollamos, por su naturaleza de cambio, es muy fácil caer en aplicarla mal… es muy probable que se vuelva contra ti y los beneficios no sean nada comparados con sus problemas a futuro.

Por eso acabamos diciendo: ante la duda… ¡no dudes! Favorece composición ante herencia.

Si quieres ampliar un poco la información te recomiendo los items 16 y 17 del libro Effective Java de Joshua Bloch y el taller que hicimos en Gigigo sobre este tema.

Además te invito a que busques por tu cuenta por Internet porque hay muchísima literatura de herencia vs composición.

¿Qué opinas sobre este tema? ¿Usas más herencia o composición? Deja tu opinión en los comentarios

Quizá también te interese…

Unidirectional Data Flow: Qué es y cómo funciona en Android

Unidirectional Data Flow: Qué es y cómo funciona en Android

Hay algunos conceptos que están empezando a resonar muy fuerte en Android, y Unidirectional Data Flow es uno de ellos. Como puede que sepas si estás apuntado a la newsletter, me he planteado escribir una serie de artículos sobre MVI (Model View Intent), y me he topado...

15 Comentarios

  1. neoranga55

    Magnífico artículo Antonio.
    Hace poco he descubierto los nuevos Default Methods de Java 8 (http://docs.oracle.com/javase/tutorial/java/IandI/defaultmethods.html) y supongo que son perfectos para olvidarse del caso de uso que mencionas en Template Methods, esto es, tengo dos clases A&B que necesitan implementar una interfaz y la implementación es la misma, en vez de usar una clase abstracta con la implementación y extender A&B de la clase abstracta, ahora A&B pueden implementar un interfaz que contiene la implementación de la clase abstracta. ¿Se te ocurren más casos de uso?

    Responder
    • Sergio Martínez Rodríguez

      Hola!, me alegro que te haya gustado el artículo y me alegro el doble que participes de forma activa en los comentarios aportando nuevas ideas sobre Java 8.

      Como bien dices los Default method y la versatilidad de la cual se ha dotado a las interfaces en Java 8 nos abre la puerta a esa implementación que comentas y a muchas más ideas que iremos descubriendo poco a poco.

      Sin embargo, en mi opinión, tenemos que prestar atención a que todos estos conceptos son nuevos y hay que tener en cuenta que el uso no ha de ser como el de “una herencia más limpia” ya que por debajo los default method no funcionan como un método de una clase padre sino como una implementación compartida que se añade en tiempo de ejecución a los elementos, al menos hasta donde yo se, tampoco he tenido tiempo de destripar Java 8 aún XD.

      Esto a su vez trae otras implicaciones: los default method deberían ser métodos de alto nivel y de propósito general a tu interfaz que sigue siendo la protagonista y no deberían recibir por argumento objetos “atados” a una o dos implementaciones concretas de tu interfaz. En lugar de ello como posible solución podrías hacer una especialización de esa interfaz para casos concretos en los cuales necesites tu default method. Aún así como digo hay mucho que jugar aún con las interfaces de Java 8. 😉

      Un saludo!

      Responder
  2. hades87

    Muy interesante este tema, lo llevo escuchando desde hace mucho y cada vez le veo mas utilidad a usar composición para muchos temas, sobretodo por lo que has comentado de separar y reutilizar código y que la clase que los implementa no ha de saber como se hacen las cosas que hace la clase que implementa.

    Responder
  3. Carlos Martínez

    Sergio, excelente artículo que explica las diferencias entre herencia y composición de una forma realmente amena y clara.

    Tengo que decir que siempre he solido decantarme por la herencia, pero creo que a partir de ahora miraré la composición con un punto de vista realmente más interesante.

    Por un caso, tienes blog personal Sergio¿?

    Responder
    • Sergio Martínez Rodríguez

      ¡Hola Carlos!, ¡encantado de que te guste y de que haya servido para que te vuelvas a plantear alguna que otra cosa!

      Mi blog personal es https://fsergio101.github.io/ pero sólo tengo un par de entradas sobre Dagger 2, está bastante abandonado porque últimamente vengo colaborando con Antonio en DevExperto ya que me parece una iniciativa iniciativa interesante. De todos modos, tengo que darle algo de “vidilla” de vez en cuando así que échale un vistazo algún día que alomejor publico alguna entrada. ;).

      Saludos

      Responder
  4. Tomás González

    Muy buen post, me ha ayudado a aclarar mis dudas sobre el abuso de herencia 🙂

    PD: ¿”Efectos de lado” no suena mal en español? Suena como a algún fenómeno físico en vez de a “daño colateral” en el código :s

    Responder
    • Antonio Leiva

      Jejej, es lo que tiene traducir conceptos en inglés, que a veces no suenan demasiado bien en español.

      Responder
  5. mdrubio

    Buenísimo y muy didáctico. No esperaba que leyendo un solo post me quedara tan claro la diferencia entre herencia y composición.
    Enhorabuena!

    Responder
  6. Valentin Cassino

    Muy buen articulo . Soy algo nuevo en esto y la verdad me sacaste una gran duda y me hiciste ver la importancia que tiene composición a la hora de modificar el código, y aparte vi como usar bien herencia . Gracias muy bueno !

    Responder
  7. José Antonio Martínez

    Gracias por compartir estos conocimientos!
    Excelente artículo y muy didáctico.
    Enhorabuena.

    Responder
  8. Esnaider Tapias

    Amigo no se si leerás mi comentario, pero muchísimas gracias. Este post es una maravilla. Tu explicación es sencilla pero precisa y ademas mencionas detalles interesantes que no había leído en otros sitios. Me encanto las analogías que usaste porque le dieron muchísima claridad a lo que querías enseñar. Un abrazo desde Colombia.

    Responder
  9. Tito José Rosendo C.

    Gracias amigo Sergio. Qué buena redacción de tu valiosa experiencia hermano, Dios te cuide. Estoy comenzando a desarrollar un proyecto propio. Estaremos en contacto.

    Responder
  10. Antonio García

    Buenas y gracias por el artículo Sergio…

    Al margen de palmaditas en la espalda, voy a intentar lanzar una crítica que intenta ser constructiva de cara a la exposición y convencimiento de lo que se pretende.

    Creo que suele ser común y confunso (para lo que me incluyo), que el autor de los ejemplos opte por el camino fácil… y para explicar la herencia, opte por un ejemplo abstracto donde el lector es capaz de ver que 4 modelos distintos de bicicletas, son en sí una bicicleta (Herencia bastante clara). El problema viene cuando ahora para explicar la composición, cojemos un coche y sus “componentes”. Chapó… queda muy claro para el lector el “qué es la composición” ya que hemos conseguido que lo visualice con un ejemplo cotidiano, Una vez que ambos “patrones” están claros… el problema real viene con… “¿cómo yo como usuario voy a a encontrarme con el caso de uso de los modelos de bicicleta y voy a aplicar la composición?”.

    En definitiva… ¿no sería más constructivo que aunque usemos el ejemplo perfecto para la composición, usemos el caso del ejemplo anterior donde hemos aplicado la herencia y lo “convirtamos” a composición? De esa forma realmente es donde ser verían las lagunas reales a los que el ingeniero de software se enfrenta. Es decir, aplicar composición donde mentalmente vemos herencia, como bien se pretendía en ese ejemplo de bicicletas.

    Muchas gracias y como decía… UN ARTÍCULO GENIAL Y MUY COMPLETO

    Responder

Enviar un comentario

Los datos personales que proporciones a través de este formulario quedarán registrados en un fichero de Antonio Leiva Gordillo, con el fin de gestionar los comentarios que realizas en este blog. La legitimación se realiza a través del consentimiento de la parte interesada. Si no se acepta, no podrás comentar en este blog. Los datos que proporciona solo se utilizan para evitar el correo no deseado y no se usarán para nada más. Puede ejercer los derechos de acceso, rectificación, cancelación y oposición en contacto@devexperto.com.

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Acepto la política de privacidad *