¿Prefiere la composición sobre la herencia?

¿Por qué preferir la composición a la herencia? ¿Qué compensaciones hay para cada enfoque? ¿Cuándo debe elegir la herencia sobre la composición?

Prefiere la composición en lugar de la herencia, ya que es más maleable / fácil de modificar más tarde, pero no utilices un enfoque de redactar siempre. Con la composición, es fácil cambiar el comportamiento sobre la marcha con Dependency Injection / Setters. La herencia es más rígida ya que la mayoría de los idiomas no le permiten derivar de más de un tipo. Entonces el ganso está más o menos cocinado una vez que deriva de TypeA.

Mi prueba de ácido para lo anterior es:

  • ¿El Tipo B quiere exponer la interfaz completa (todos los métodos públicos, no menos) de la Tipo A de modo que el Tipo B se pueda usar donde se espera Tipo A? Indica herencia .

por ejemplo, un Cessna biplane expondrá la interfaz completa de un avión, si no más. Eso lo hace apropiado para derivar de Avión.

  • ¿El Tipo B solo quiere algo / parte del comportamiento expuesto por TypeA? Indica necesidad de composición.

por ejemplo, un pájaro puede necesitar solo el comportamiento de vuelo de un avión. En este caso, tiene sentido extraerlo como una interfaz / clase / y ambos y convertirlo en miembro de ambas clases.

Actualización: Acabo de volver a mi respuesta y parece ahora que está incompleta sin una mención específica del Principio de Sustitución de Liskov de Barbara Liskov como una prueba para ‘¿Debería heredar de este tipo?’

Piensa en la contención como una relación. Un automóvil “tiene un” motor, una persona “tiene un” nombre, etc.

Piensa en la herencia como una relación. Un automóvil “es un” vehículo, una persona “es un” mamífero “, etc.

No me atribuyo ningún crédito por este enfoque. Lo tomé directamente de la Segunda Edición de Code Complete por Steve McConnell , Sección 6.3 .

Si entiendes la diferencia, es más fácil de explicar.

Código de procedimiento

Un ejemplo de esto es PHP sin el uso de clases (particularmente antes de PHP5). Toda la lógica está codificada en un conjunto de funciones. Puede incluir otros archivos que contengan funciones auxiliares, y así sucesivamente, y llevar a cabo su lógica de negocios al pasar datos en funciones. Esto puede ser muy difícil de administrar a medida que la aplicación crece. PHP5 intenta remediar esto ofreciendo un diseño más orientado a objetos.

Herencia

Esto fomenta el uso de clases. La herencia es uno de los tres principios del diseño OO (herencia, polymorphism, encapsulación).

class Person { String Title; String Name; Int Age } class Employee : Person { Int Salary; String Title; } 

Esto es herencia en el trabajo. El empleado “es una” persona o hereda de una persona. Todas las relaciones de herencia son relaciones “es-a”. El empleado también sombrea la propiedad del Título de Persona, lo que significa Employee.Title devolverá el Título para el Empleado, no la Persona.

Composición

La composición se ve favorecida por la herencia. Para decirlo de manera simple, tendrías:

 class Person { String Title; String Name; Int Age; public Person(String title, String name, String age) { this.Title = title; this.Name = name; this.Age = age; } } class Employee { Int Salary; private Person person; public Employee(Person p, Int salary) { this.person = p; this.Salary = salary; } } Person johnny = new Person ("Mr.", "John", 25); Employee john = new Employee (johnny, 50000); 

La composición es típicamente una relación “tiene una” o “usa una”. Aquí la clase Empleado tiene una Persona. No hereda de Persona, sino que obtiene el objeto Persona que se le pasa, por lo que “tiene una” Persona.

Composición sobre herencia

Ahora di que quieres crear un tipo de administrador para que termines con:

 class Manager : Person, Employee { ... } 

Este ejemplo funcionará bien, sin embargo, ¿qué sucede si la Persona y el Empleado declararon el Title ? ¿Debería Manager.Title devolver “Manager of Operations” o “Mr.”? En composición, esta ambigüedad se maneja mejor:

 Class Manager { public Title; public Manager(Person p, Employee e) { this.Title = e.Title; } } 

El objeto Manager está compuesto como un Empleado y una Persona. El comportamiento del título se toma del empleado. Esta composición explícita elimina la ambigüedad entre otras cosas y encontrará menos errores.

Con todos los beneficios innegables proporcionados por la herencia, estas son algunas de sus desventajas.

Desventajas de la herencia:

  1. No puede cambiar la implementación heredada de las súper clases en el tiempo de ejecución (obviamente porque la herencia se define en tiempo de comstackción).
  2. La herencia expone una subclase a detalles de la implementación de clase de su padre, por eso a menudo se dice que la herencia rompe la encapsulación (en un sentido que realmente necesita enfocarse en las interfaces, no en la implementación, por lo que no siempre es preferible reutilizarlas por subclasificación).
  3. El estrecho acoplamiento proporcionado por la herencia hace que la implementación de una subclase esté muy ligada a la implementación de una superclase que cualquier cambio en la implementación principal obligará a la subclase a cambiar.
  4. La reutilización excesiva por subclasificación puede hacer que la stack de herencia sea muy profunda y muy confusa también.

Por otro lado, la composición de objetos se define en el tiempo de ejecución a través de objetos que adquieren referencias a otros objetos. En tal caso, estos objetos nunca podrán alcanzar los datos protegidos de los demás (sin interrupción de encapsulado) y se verán obligados a respetar la interfaz de cada uno. Y en este caso también, las dependencias de implementación serán mucho menos que en el caso de la herencia.

Otra razón, muy pragmática, para preferir la composición sobre la herencia tiene que ver con su modelo de dominio y asignarlo a una base de datos relacional. Es realmente difícil mapear la herencia al modelo SQL (terminas con todo tipo de soluciones hacky, como crear columnas que no siempre se usan, usar vistas, etc.). Algunos ORML intentan lidiar con esto, pero siempre se complica rápidamente. La composición se puede modelar fácilmente a través de una relación de clave externa entre dos tablas, pero la herencia es mucho más difícil.

Mientras que en palabras cortas estoy de acuerdo con “Prefiero la composición sobre la herencia”, muy a menudo para mí suena como “preferir las patatas a la coca-cola”. Hay lugares para la herencia y lugares para la composición. Necesitas entender la diferencia, entonces esta pregunta desaparecerá. Lo que realmente significa para mí es “si vas a usar la herencia, piensa de nuevo, es probable que necesites la composición”.

Deberías preferir las papas a la coca cola cuando quieres comer, y la coca cola a las papas cuando quieres beber.

Crear una subclase debería significar algo más que una forma conveniente de llamar a los métodos de superclase. Debería usar la herencia cuando la subclase “es-una” superclase sea estructural y funcionalmente, cuando se puede usar como superclase y va a usar eso. Si no es el caso, no es herencia, sino algo más. Composición es cuando sus objetos consisten en otro, o tienen alguna relación con ellos.

Entonces, para mí, parece que si alguien no sabe si necesita herencia o composición, el verdadero problema es que no sabe si quiere beber o comer. Piense más sobre su dominio problemático, entiéndalo mejor.

La herencia es bastante tentadora, especialmente viniendo de terrenos de procedimiento y a menudo se ve engañosamente elegante. Quiero decir que todo lo que necesito hacer es agregar esta funcionalidad a alguna otra clase, ¿verdad? Bueno, uno de los problemas es que

herencia es probablemente la peor forma de acoplamiento que puede tener

Su clase base rompe la encapsulación al exponer los detalles de implementación a las subclases en forma de miembros protegidos. Esto hace que tu sistema sea rígido y frágil. Sin embargo, la falla más trágica es que la nueva subclase trae consigo todo el bagaje y la opinión de la cadena de herencia.

El artículo, Inheritance is Evil: The Epic Fail of the DataAnnotationsModelBinder , repasa un ejemplo de esto en C #. Muestra el uso de la herencia cuando se debería haber usado la composición y cómo se puede refactorizar.

En Java o C #, un objeto no puede cambiar su tipo una vez que se ha instanciado.

Por lo tanto, si su objeto necesita aparecer como un objeto diferente o comportarse de manera diferente según el estado o las condiciones de un objeto, entonces use Composición : Consulte Patrones de diseño de estado y estrategia .

Si el objeto necesita ser del mismo tipo, entonces use Herencia o implemente interfaces.

Personalmente aprendí a preferir siempre la composición sobre la herencia. No hay problema programático que pueda resolver con herencia que no pueda resolver con la composición; aunque puede que tenga que usar Interfaces (Java) o Protocolos (Obj-C) en algunos casos. Como C ++ no sabe nada de eso, tendrá que usar clases base abstractas, lo que significa que no puede deshacerse por completo de la herencia en C ++.

La composición suele ser más lógica, proporciona una mejor abstracción, una mejor encapsulación, una mejor reutilización del código (especialmente en proyectos muy grandes) y es menos probable que rompa algo a distancia simplemente porque ha realizado un cambio aislado en cualquier parte de su código. También hace que sea más fácil mantener el ” Principio de Responsabilidad Individual “, que a menudo se resume como ” Nunca debe haber más de una razón para que una clase cambie “, y significa que cada clase existe para un propósito específico y debería solo tienen métodos que están directamente relacionados con su propósito. Además, tener un árbol de herencia muy poco profundo hace que sea mucho más fácil mantener la visión general incluso cuando el proyecto comienza a ser realmente grande. Mucha gente piensa que la herencia representa nuestro mundo real bastante bien, pero esa no es la verdad. El mundo real usa mucha más composición que herencia. Casi todos los objetos del mundo real que puedes sostener en tu mano han sido compuestos de otros objetos más pequeños del mundo real.

Sin embargo, hay aspectos negativos de la composición. Si omite la herencia por completo y solo se enfoca en la composición, notará que a menudo tiene que escribir un par de líneas de código adicionales que no eran necesarias si había usado la herencia. A veces también te obligan a repetirte y esto viola el principio DRY (SECO = No repetir). Además, la composición a menudo requiere delegación, y un método es simplemente llamar a otro método de otro objeto sin otro código que rodee esta llamada. Tales “llamadas al método doble” (que pueden extenderse fácilmente a llamadas a métodos triples o cuádruples e incluso más allá de eso) tienen un rendimiento mucho peor que la herencia, donde simplemente heredas un método de tu padre. Llamar a un método heredado puede ser tan rápido como llamar a uno no heredado, o puede ser un poco más lento, pero generalmente es más rápido que dos llamadas a métodos consecutivos.

Puede haber notado que la mayoría de los lenguajes OO no permiten herencia múltiple. Si bien hay un par de casos en que la herencia múltiple realmente puede comprar algo, pero esas son más bien excepciones que la regla. Cada vez que se encuentre con una situación en la que piense que “la herencia múltiple sería una característica realmente genial para resolver este problema”, generalmente se encuentra en un punto en el que debe volver a pensar en la herencia, ya que incluso puede requerir un par de líneas de código adicionales. , una solución basada en la composición generalmente resultará ser mucho más elegante, flexible y a prueba de futuro.

La herencia es realmente una característica interesante, pero me temo que se ha usado en exceso en los últimos años. Las personas trataban la herencia como el único martillo que puede clavarlo todo, independientemente de si era en realidad un clavo, un tornillo o tal vez algo completamente diferente.

No encontré una respuesta satisfactoria aquí, así que escribí una nueva.

Para entender por qué ” prefieren la composición sobre la herencia”, primero tenemos que recuperar la suposición omitida en este lenguaje abreviado.

Hay dos beneficios de la herencia: subtipificación y subclases

  1. Subtipificar significa conformarse a una firma de tipo (interfaz), es decir, un conjunto de API, y se puede anular parte de la firma para lograr el polymorphism de subtipado.

  2. Subclasificación significa la reutilización implícita de implementaciones de métodos.

Con los dos beneficios surgen dos propósitos diferentes para hacer herencia: orientar la subtipificación y reutilizar el código.

Si el único propósito es reutilizar el código, la subclasificación puede dar uno más de lo que necesita, es decir, algunos métodos públicos de la clase principal no tienen mucho sentido para la clase de los niños. En este caso, en lugar de favorecer la composición sobre la herencia, se exige la composición. Aquí también es de donde proviene la noción “is-a” vs. “has-a”.

Entonces, solo cuando se propone la subtipificación, es decir, para utilizar la nueva clase más tarde de forma polimórfica, ¿nos enfrentamos al problema de elegir herencia o composición? Esta es la suposición que se omite en el idioma acortado que se discute.

Subtipificar es conformarse a una firma de tipo, esto significa que la composición siempre debe exponer una cantidad no menor de API del tipo. Ahora las compensaciones entran en juego:

  1. La herencia proporciona una reutilización simple del código si no se reemplaza, mientras que la composición tiene que volver a codificar cada API, incluso si es simplemente un trabajo simple de delegación.

  2. La herencia proporciona recursión abierta directa a través del sitio polimórfico interno this , es decir, invocando el método de anulación (o incluso el tipo ) en otra función miembro, ya sea pública o privada (aunque desaconsejada ). La recursión abierta se puede simular a través de la composición , pero requiere un esfuerzo adicional y puede no ser siempre viable (?). Esta respuesta a una pregunta duplicada habla algo similar.

  3. La herencia expone a los miembros protegidos . Esto rompe el encapsulamiento de la clase padre, y si se usa por subclase, se introduce otra dependencia entre el hijo y su padre.

  4. La composición tiene la ventaja de invertir el control, y su dependencia puede inyectarse dinámicamente, como se muestra en el patrón de decorador y en el patrón de proxy .

  5. La composición tiene el beneficio de la progtwigción orientada a combinador , es decir, funciona de una manera similar al patrón compuesto .

  6. La composición sigue inmediatamente a la progtwigción de una interfaz .

  7. La composición tiene el beneficio de una herencia múltiple fácil.

Teniendo en cuenta las compensaciones anteriores, preferimos la composición por sobre la herencia. Sin embargo, para las clases estrechamente relacionadas, es decir, cuando la reutilización implícita del código realmente produce beneficios o se desea el poder mágico de la recursión abierta, la herencia será la elección.

Mi regla general: antes de usar la herencia, considere si la composición tiene más sentido.

Motivo: Subclase generalmente significa más complejidad y conexión, es decir, más difícil de cambiar, mantener y escalar sin cometer errores.

Una respuesta mucho más completa y concreta de Tim Boudreau de Sun:

Los problemas más comunes del uso de la herencia tal como lo veo son:

  • Los actos inocentes pueden tener resultados inesperados . El ejemplo clásico de esto son las llamadas a métodos invalidables del constructor de la superclase, antes de que se hayan inicializado los campos de la instancia de subclases. En un mundo perfecto, nadie haría eso nunca. Este no es un mundo perfecto.
  • Ofrece tentaciones perversas para que los subclasistas realicen suposiciones sobre el orden de las llamadas a los métodos, y esas suposiciones tienden a no ser estables si la superclase puede evolucionar con el tiempo. Ver también mi analogía tostadora y cafetera .
  • Las clases se vuelven más pesadas : no necesariamente sabes qué trabajo está haciendo tu superclase en su constructor, o cuánta memoria va a usar. Entonces, construir un inocente objeto ligero podría ser mucho más caro de lo que piensas, y esto puede cambiar con el tiempo si la superclase evoluciona
  • Alienta una explosión de subclases . La carga de clases cuesta tiempo, más clases cuestan memoria. Esto puede no ser un problema hasta que estés lidiando con una aplicación en la escala de NetBeans, pero ahí tuvimos problemas reales con, por ejemplo, que los menús sean lentos porque la primera pantalla de un menú provocó una enorme carga de clases. Arreglamos esto moviéndonos a una syntax más declarativa y otras técnicas, pero eso también cuesta tiempo para solucionarlo.
  • Hace que sea más difícil cambiar las cosas más tarde ; si has hecho pública una clase, cambiar la clase superior va a romper las subclases, es una opción que, una vez que has hecho público el código, estás casado. Entonces, si no está alterando la funcionalidad real de su superclase, obtendrá mucha más libertad para cambiar las cosas más adelante si usa, en lugar de extender lo que necesita. Tomemos, por ejemplo, la subclasificación de JPanel: esto suele ser incorrecto; y si la subclase es pública en alguna parte, nunca tendrá la oportunidad de volver a tomar esa decisión. Si se accede como JComponent getThePanel (), aún puede hacerlo (sugerencia: exponer modelos para los componentes dentro de su API).
  • Las jerarquías de objetos no se escalan (o hacer que escale más adelante es mucho más difícil que planificar con anticipación) : este es el problema clásico de “demasiadas capas”. Voy a entrar en esto a continuación, y cómo el patrón AskTheOracle puede resolverlo (aunque puede ofender a los puristas OOP).

Mi opinión sobre qué hacer, si permite la herencia, que puede tomar con un grano de sal es:

  • No mostrar campos, nunca, excepto constantes
  • Los métodos serán abstractos o finales
  • No llamar a ningún método del constructor de la superclase

todo esto se aplica menos a los proyectos pequeños que a los grandes, y menos a las clases privadas que a las públicas

La herencia es muy poderosa, pero no se puede forzar (ver: el problema círculo-elipse ). Si realmente no puede estar completamente seguro de una verdadera relación de subtipo “es-a”, entonces es mejor ir con la composición.

La herencia crea una fuerte relación entre una subclase y una súperclase; La subclase debe tener en cuenta los detalles de implementación de superclase. Crear la súper clase es mucho más difícil cuando tienes que pensar en cómo se puede extender. Debe documentar las invariantes de clase cuidadosamente e indicar qué otros métodos pueden usar internamente.

La herencia a veces es útil, si la jerarquía realmente representa una relación is-a-relationship. Se relaciona con el Principio de Cerrado Abierto, que establece que las clases deben estar cerradas para su modificación pero abiertas a extensión. De esa forma puedes tener polymorphism; tener un método genérico que se ocupe del súper tipo y sus métodos, pero a través del despacho dynamic se invoca el método de la subclase. Esto es flexible y ayuda a crear direccionamiento indirecto, que es esencial en el software (para saber menos sobre los detalles de implementación).

Sin embargo, la herencia se sobreutiliza fácilmente y crea una complejidad adicional, con dependencias duras entre clases. También entender lo que sucede durante la ejecución de un progtwig se vuelve bastante difícil debido a las capas y la selección dinámica de llamadas a métodos.

Sugeriría usar la composición como el predeterminado. Es más modular y ofrece el beneficio de la vinculación tardía (puede cambiar el componente de forma dinámica). También es más fácil probar las cosas por separado. Y si necesita usar un método de una clase, no está obligado a tener cierta forma (Principio de sustitución de Liskov).

Debes echarle un vistazo al Principio de Sustitución de Liskov en los principios SÓLIDOS de diseño de clase del Tío Bob. 🙂

Supongamos que un avión tiene solo dos partes: un motor y alas.
Entonces hay dos formas de diseñar una clase de avión.

 Class Aircraft extends Engine{ var wings; } 

Ahora tu avión puede comenzar con alas fijas
y cambiarlos a alas giratorias sobre la marcha. Esencialmente
un motor con alas. Pero qué pasaría si quisiera cambiar
el motor sobre la marcha también?

O el Engine clase base expone un mutador para cambiar su
propiedades, o rediseño Aircraft como:

 Class Aircraft { var wings; var engine; } 

Ahora puedo reemplazar mi motor sobre la marcha también.

“Prefiere la composición sobre la herencia” es un principio de diseño, que dice no abusar de la herencia cuando no encaja.

Si no existe una relación jerárquica del mundo real entre dos entidades, no use la herencia, sino que use la composición. La composición representa la relación “TIENE A”.

Por ejemplo, el coche TIENE ruedas, cuerpo, motor, etc. Pero si heredas aquí, se convierte en COCHE como una rueda, lo que es incorrecto.

Para obtener más explicaciones, consulte preferir la composición a la herencia

¿Por qué preferir la composición a la herencia?

Ver otras respuestas

¿Cuándo debe elegir la herencia sobre la composición?

Siempre que la oración “un Bar es un Foo, y un Bar puede hacer todo lo que un Foo puede hacer” tiene sentido.

La sabiduría convencional dice que si la oración “un Bar es un Foo” tiene sentido, entonces es una buena pista que la elección de la herencia es apropiada. Por ejemplo, un perro es un animal, por lo tanto, tener la clase Dog heredada de Animal es probablemente un buen diseño.

Desafortunadamente, esta simple prueba “is-a” no es confiable. El problema Circle-Ellipse es un gran contraejemplo: aunque un círculo es una elipse, es una mala idea que la clase Circle herede de Ellipse, porque hay cosas que los elipses pueden hacer, pero los círculos no. Por ejemplo, las elipsis pueden estirarse, pero los círculos no pueden. Entonces, aunque puede tener ellipse.stretch() , no puede tener circle.stretch() .

Esta es la razón por la cual una mejor prueba es “un Bar es un Foo, y un Bar puede hacer todo lo que un Foo puede hacer “. Esto realmente significa que Foo se puede usar polimórficamente. La prueba “is-a” es solo una condición necesaria para el uso polimórfico, y típicamente significa que todos los captadores de Foo tienen sentido en Bar. La prueba adicional de “puede hacer todo” significa que todos los iniciadores de Foo también tienen sentido en Bar. Esta prueba adicional normalmente falla cuando una clase Bar “es-un” Foo, pero le agrega algunas restricciones, en cuyo caso no debe usar la herencia, porque Foo no se puede usar polimórficamente. En otras palabras, la herencia no se trata de compartir propiedades, sino de compartir la funcionalidad. Las clases derivadas deberían ampliar la funcionalidad de las clases base, no restringirla.

Esto es equivalente al Principio de Sustitución de Liskov :

Las funciones que usan punteros o referencias a clases base deben ser capaces de usar objetos de clases derivadas sin saberlo

Cuando quiere “copiar” / Exponer la API de la clase base, usa la herencia. Cuando solo desee “copiar” la funcionalidad, use la delegación.

Un ejemplo de esto: quieres crear una stack de una lista. Stack solo tiene pop, push y peek. No debe usar la herencia, dado que no quiere push_back, push_front, removeAt, et al.-tipo de funcionalidad en una stack.

Estas dos formas pueden vivir juntas muy bien y realmente se apoyan mutuamente.

La composición es simplemente modular: crea una interfaz similar a la clase principal, crea un objeto nuevo y delega llamadas a él. Si estos objetos no necesitan conocerse, es bastante seguro y fácil de usar. Hay tantas posibilidades aquí.

Sin embargo, si la clase para padres necesita acceder a las funciones proporcionadas por la “clase infantil” para un progtwigdor inexperto, puede parecer que es un gran lugar para usar la herencia. La clase padre simplemente puede llamar su propio resumen “foo ()” que es sobrescrito por la subclase y luego puede dar el valor a la base abstracta.

Parece una buena idea, pero en muchos casos es mejor dar a la clase un objeto que implemente el foo () (o incluso establecer el valor proporcionado el foo () manualmente) que heredar la nueva clase de alguna clase base que requiera la función foo () a ser especificada.

¿Por qué?

Porque la herencia es una forma pobre de mover información .

La composición tiene una ventaja real aquí: la relación puede invertirse: la “clase padre” u “trabajador abstracto” puede agregar cualquier objeto “hijo” específico que implemente cierta interfaz + cualquier hijo puede establecerse dentro de cualquier otro tipo de padre, que acepta es tipo . Y puede haber cualquier cantidad de objetos, por ejemplo, MergeSort o QuickSort podrían ordenar cualquier lista de objetos que implementen una interfaz de comparación abstracta. O para decirlo de otra manera: cualquier grupo de objetos que implementen “foo ()” y otro grupo de objetos que puedan hacer uso de objetos que tienen “foo ()” pueden jugar juntos.

Puedo pensar en tres razones reales para usar la herencia:

  1. Tienes muchas clases con la misma interfaz y quieres ahorrar tiempo escribiéndolas
  2. Tienes que usar la misma clase base para cada objeto
  3. Necesita modificar las variables privadas, que no pueden ser públicas en ningún caso

Si esto es cierto, entonces probablemente sea necesario usar herencia.

No hay nada malo en usar la razón 1, es muy bueno tener una interfaz sólida en sus objetos. Esto se puede hacer usando composición o herencia, no hay problema, si esta interfaz es simple y no cambia. Por lo general, la herencia es bastante efectiva aquí.

Si el motivo es el número 2, se vuelve un poco complicado. ¿De verdad solo necesitas usar la misma clase base? In general, just using the same base class is not good enough, but it may be a requirement of your framework, a design consideration which can not be avoided.

However, if you want to use the private variables, the case 3, then you may be in trouble. If you consider global variables unsafe, then you should consider using inheritance to get access to private variables also unsafe . Mind you, global variables are not all THAT bad – databases are essentially big set of global variables. But if you can handle it, then it’s quite fine.

Aside from is a/has a considerations, one must also consider the “depth” of inheritance your object has to go through. Anything beyond five or six levels of inheritance deep might cause unexpected casting and boxing/unboxing problems, and in those cases it might be wise to compose your object instead.

A simple way to make sense of this would be that inheritance should be used when you need an object of your class to have the same interface as its parent class, so that it can thereby be treated as an object of the parent class (upcasting). Moreover, function calls on a derived class object would remain the same everywhere in code, but the specific method to call would be determined at runtime (ie the low-level implementation differs, the high-level interface remains the same).

Composition should be used when you do not need the new class to have the same interface, ie you wish to conceal certain aspects of the class’ implementation which the user of that class need not know about. So composition is more in the way of supporting encapsulation (ie concealing the implementation) while inheritance is meant to support abstraction (ie providing a simplified representation of something, in this case the same interface for a range of types with different internals).

When you have an is-a relation between two classes (example dog is a canine), you go for inheritance.

On the other hand when you have has-a or some adjective relationship between two classes (student has courses) or (teacher studies courses), you chose composition.

Subtyping is appropriate and more powerful where the invariants can be enumerated , else use function composition for extensibility.

I agree with @Pavel, when he says, there are places for composition and there are places for inheritance.

I think inheritance should be used if your answer is an affirmative to any of these questions.

  • Is your class part of a structure that benefits from polymorphism ? For example, if you had a Shape class, which declares a method called draw(), then we clearly need Circle and Square classes to be subclasses of Shape, so that their client classes would depend on Shape and not on specific subclasses.
  • Does your class need to re-use any high level interactions defined in another class ? The template method design pattern would be impossible to implement without inheritance. I believe all extensible frameworks use this pattern.

However, if your intention is purely that of code re-use, then composition most likely is a better design choice.

A rule of thumb I have heard is inheritance should be used when its a “is-a” relationship and composition when its a “has-a”. Even with that I feel that you should always lean towards composition because it eliminates a lot of complexity.

Inheritance is a very powerfull machanism for code reuse. But needs to be used properly. I would say that inheritance is used correctly if the subclass is also a subtype of the parent class. As mentioned above, the Liskov Substitution Principle is the key point here.

Subclass is not the same as subtype. You might create subclasses that are not subtypes (and this is when you should use composition). To understand what a subtype is, lets start giving an explanation of what a type is.

When we say that the number 5 is of type integer, we are stating that 5 belongs to a set of possible values (as an example, see the possible values for the Java primitive types). We are also stating that there is a valid set of methods I can perform on the value like addition and subtraction. And finally we are stating that there are a set of properties that are always satisfied, for example, if I add the values 3 and 5, I will get 8 as a result.

To give another example, think about the abstract data types, Set of integers and List of integers, the values they can hold are restricted to integers. They both support a set of methods, like add(newValue) and size(). And they both have different properties (class invariant), Sets does not allow duplicates while List does allow duplicates (of course there are other properties that they both satisfy).

Subtype is also a type, which has a relation to another type, called parent type (or supertype). The subtype must satisfy the features (values, methods and properties) of the parent type. The relation means that in any context where the supertype is expected, it can be substitutable by a subtype, without affecting the behaviour of the execution. Let’s go to see some code to exemplify what I’m saying. Suppose I write a List of integers (in some sort of pseudo language):

 class List { data = new Array(); Integer size() { return data.length; } add(Integer anInteger) { data[data.length] = anInteger; } } 

Then, I write the Set of integers as a subclass of the List of integers:

 class Set, inheriting from: List { add(Integer anInteger) { if (data.notContains(anInteger)) { super.add(anInteger); } } } 

Our Set of integers class is a subclass of List of Integers, but is not a subtype, due to it is not satisfying all the features of the List class. The values, and the signature of the methods are satisfied but the properties are not. The behaviour of the add(Integer) method has been clearly changed, not preserving the properties of the parent type. Think from the point of view of the client of your classes. They might receive a Set of integers where a List of integers is expected. The client might want to add a value and get that value added to the List even if that value already exist in the List. But her wont get that behaviour if the value exists. A big suprise for her!

This is a classic example of an improper use of inheritance. Use composition in this case.

(a fragment from: use inheritance properly ).

Composition v/s Inheritance is a wide subject. There is no real answer for what is better as I think it all depends on the design of the system.

Generally type of relationship between object provide better information to choose one of them.

If relation type is “IS-A” relation then Inheritance is better approach. otherwise relation type is “HAS-A” relation then composition will better approach.

Its totally depend on entity relationship.

To address this question from a different perspective for newer programmers:

Inheritance is often taught early when we learn object-oriented programming, so it’s seen as an easy solution to a common problem.

I have three classes that all need some common functionality. So if I write a base class and have them all inherit from it, then they will all have that functionality and I’ll only need to maintain it in once place.

It sounds great, but in practice it almost never, ever works, for one of several reasons:

  • We discover that there are some other functions that we want our classes to have. If the way that we add functionality to classes is through inheritance, we have to decide – do we add it to the existing base class, even though not every class that inherits from it needs that functionality? Do we create another base class? But what about classes that already inherit from the other base class?
  • We discover that for just one of the classes that inherits from our base class we want the base class to behave a little differently. So now we go back and tinker with our base class, maybe adding some virtual methods, or even worse, some code that says, “If I’m inherited type A, do this, but if I’m inherited type B, do that.” That’s bad for lots of reasons. One is that every time we change the base class, we’re effectively changing every inherited class. So we’re really changing class A, B, C, and D because we need a slightly different behavior in class A. As careful as we think we are, we might break one of those classes for reasons that have nothing to do with those classes.
  • We might know why we decided to make all of these classes inherit from each other, but it might not (probably won’t) make sense to someone else who has to maintain our code. We might force them into a difficult choice – do I do something really ugly and messy to make the change I need (see the previous bullet point) or do I just rewrite a bunch of this.

In the end, we tie our code in some difficult knots and get no benefit whatsoever from it except that we get to say, “Cool, I learned about inheritance and now I used it.” That’s not meant to be condescending because we’ve all done it. But we all did it because no one told us not to.

As soon as someone explained “favor composition over inheritance” to me, I thought back over every time I tried to share functionality between classes using inheritance and realized that most of the time it didn’t really work well.

The antidote is the Single Responsibility Principle . Think of it as a constraint. My class must do one thing. I must be able to give my class a name that somehow describes that one thing it does. (There are exceptions to everything, but absolute rules are sometimes better when we’re learning.) It follows that I cannot write a base class called ObjectBaseThatContainsVariousFunctionsNeededByDifferentClasses . Whatever distinct functionality I need must be in its own class, and then other classes that need that functionality can depend on that class, not inherit from it.

At the risk of oversimplifying, that’s composition – composing multiple classes to work together. And once we form that habit we find that it’s much more flexible, maintainable, and testable than using inheritance.

As many people told, I will first start with the check – whether there exists an “is-a” relationship. If it exists I usually check the following:

Whether the base class can be instantiated. That is, whether the base class can be non-abstract. If it can be non-abstract I usually prefer composition

Eg 1. Accountant is an Employee. But I will not use inheritance because a Employee object can be instantiated.

Eg 2. Book is a SellingItem. A SellingItem cannot be instantiated – it is abstract concept. Hence I will use inheritacne. The SellingItem is an abstract base class (or interface in C#)

What do you think about this approach?

Also, I support @anon answer in Why use inheritance at all?

The main reason for using inheritance is not as a form of composition – it is so you can get polymorphic behaviour. If you don’t need polymorphism, you probably should not be using inheritance.

@MatthieuM. says in https://softwareengineering.stackexchange.com/questions/12439/code-smell-inheritance-abuse/12448#comment303759_12448

The issue with inheritance is that it can be used for two orthogonal purposes:

interface (for polymorphism)

implementation (for code reuse)

REFERENCE

  1. Which class design is better?
  2. Inheritance vs. Aggregation

Even though Composition is preferred, I would like to highlight pros of Inheritance and cons of Composition .

Pros of Inheritance:

  1. It establishes a logical ” IS A” relation. If Car and Truck are two types of Vehicle ( base class), child class IS A base class.

    es decir

    Car is a Vehicle

    Truck is a Vehicle

  2. With inheritance, you can define/modify/extend a capability

    1. Base class provides no implementation and sub-class has to override complete method (abstract) => You can implement a contract
    2. Base class provides default implementation and sub-class can change the behaviour => You can re-define contract
    3. Sub-class adds extension to base class implementation by calling super.methodName() as first statement => You can extend a contract
    4. Base class defines structure of the algorithm and sub-class will override a part of algorithm => You can implement Template_method without change in base class skeleton

Cons of Composition:

  1. In inheritance, subclass can directly invoke base class method even though it’s not implementing base class method because of IS A relation. If you use composition, you have to add methods in container class to expose contained class API

eg If Car contains Vehicle and if you have to get price of the Car , which has been defined in Vehicle , your code will be like this

 class Vehicle{ protected double getPrice(){ // return price } } class Car{ Vehicle vehicle; protected double getPrice(){ return vehicle.getPrice(); } } 
    Intereting Posts