Java omite la herencia múltiple debido a que obvia el objetivo de diseño de mantener el lenguaje simple .
Me pregunto si Java (con su ecosistema) es realmente "simple". Python no es complejo y tiene herencia múltiple. Entonces, sin ser demasiado subjetivo, mi pregunta es ...
¿Cuáles son los patrones de problemas típicos que se benefician de un código diseñado para hacer un uso intensivo de la herencia múltiple?
multiple-inheritance
codificador de árboles
fuente
fuente
Respuestas:
Pros:
Contras :
En C ++, un buen ejemplo de herencia múltiple utilizada para componer características ortogonales es cuando usa CRTP para, por ejemplo, configurar un sistema de componentes para un juego.
Empecé a escribir un ejemplo, pero creo que vale la pena mirar un ejemplo del mundo real. Algún código de Ogre3D usa herencia múltiple de una manera agradable y muy intuitiva. Por ejemplo, la clase Mesh hereda de Resources y AnimationContainer. Los recursos exponen la interfaz común a todos los recursos y AnimationContainer expone la interfaz específica para manipular un conjunto de animaciones. No están relacionados, por lo que es fácil pensar en una malla como un recurso que, además, puede contener un conjunto de animaciones. Se siente natural, ¿no?
Puede ver otros ejemplos en esta biblioteca , como la forma en que la asignación de memoria se gestiona de forma multada haciendo que las clases hereden de variantes de una sobrecarga de clases CRTP nuevas y eliminadas.
Como se dijo, los principales problemas con la herencia múltiple surgen de mezclar conceptos relacionados. Hace que el lenguaje tenga que establecer implementaciones complejas (vea la forma en que C ++ permite jugar con el problema del diamante ...) y el usuario no está seguro de lo que sucede en esa implementación. Por ejemplo, lea este artículo que explica cómo se implementa en C ++ .
Eliminarlo del idioma ayuda a evitar que las personas que no saben cómo se informa el idioma hagan las cosas malas. Pero obliga a pensar de una manera que, a veces, no se siente natural, incluso si se trata de casos extremos, sucede con más frecuencia de lo que piensas.
fuente
Hay un concepto llamado mixins que se usa mucho en lenguajes más dinámicos. La herencia múltiple es una forma en la que un lenguaje puede admitir mixins. Los mixins se usan generalmente como una forma para que una clase acumule diferentes piezas de funcionalidad. Sin herencia múltiple, debe usar la agregación / delegación para obtener un comportamiento de tipo mixin con una clase, que es un poco más sintáctica.
fuente
Creo que la elección se basa principalmente en cuestiones debidas al problema del diamante .
Además, a menudo es posible eludir el uso de la herencia múltiple por delegación u otros medios.
No estoy seguro del significado de tu última pregunta. Pero si es "¿en qué casos es útil la herencia múltiple?", Entonces, en todos los casos en que le gustaría tener un objeto A que tenga funcionalidades de los objetos B y C, básicamente.
fuente
No profundizaré mucho aquí, pero seguramente puedes entender la herencia múltiple en Python a través del siguiente enlace http://docs.python.org/release/1.5.1p1/tut/multiple.html :
...
Este es solo un pequeño párrafo, pero lo suficientemente grande como para despejar las dudas, supongo.
fuente
Un lugar donde la herencia múltiple sería útil es una situación en la que una clase implementa varias interfaces, pero le gustaría tener alguna funcionalidad predeterminada incorporada en cada interfaz. Esto es útil si la mayoría de las clases que implementan alguna interfaz quieren hacer algo de la misma manera, pero ocasionalmente necesitas hacer algo diferente. Puede tener cada clase con la misma implementación, pero tiene más sentido empujarla hacia arriba en una ubicación.
fuente
Este es solo un ejemplo, pero me parece invaluable para mejorar la seguridad y mitigar las tentaciones de aplicar cambios en cascada a través de las personas que llaman o las subclases.
Donde he encontrado que la herencia múltiple es increíblemente útil incluso para las interfaces más abstractas y sin estado es el idioma de interfaz no virtual (NVI) en C ++.
Ni siquiera son clases base realmente abstractas, sino interfaces que solo tienen un poco de implementación para hacer cumplir los aspectos universales de sus contratos, ya que en realidad no están reduciendo la generalidad del contrato, sino más bien haciéndolo cumplir mejor .
Ejemplo simple (algunos podrían comprobar que un identificador de archivo pasado está abierto o algo así):
En este caso, quizás
f
sea llamado por mil lugares en la base de código, mientras quef_impl
es anulado por cien subclases.Sería difícil hacer este tipo de verificación de seguridad en los 1000 lugares que llaman
f
o en los 100 lugares que anulanf_impl
.Al hacer que este punto de entrada a la funcionalidad no sea virtual, me da un lugar central para realizar esta verificación. Y esta verificación no está reduciendo la abstracción en lo más mínimo, ya que simplemente está afirmando una condición previa requerida para llamar a esta función. En cierto sentido, podría decirse que fortalece el contrato proporcionado por la interfaz y alivia la carga de verificar la
x
entrada para asegurarse de que se ajuste a las condiciones previas válidas en los 100 lugares que la anulan.Es algo que desearía que todos los lenguajes tuvieran, y también deseaba, incluso en C ++, que fuera un concepto un poco más nativo (por ejemplo: no nos obliga a definir una función separada para anular).
Esto es extremadamente útil si no lo hizo
assert
por adelantado, y se dio cuenta de que lo necesitaba más tarde cuando algunos lugares aleatorios en la base de código encontraban valores negativos que se les pasabanf
.fuente
Primero: múltiples copias de la clase base (un problema de C ++) y un acoplamiento estrecho entre las clases base y derivadas.
Segundo: herencia múltiple de interfaces abstractas
fuente