miércoles, agosto 02, 2006

"Herencia múltiple en PHP5"

Este es un resumen de conclusiones que se vertieron en una discusión sobre el tema en Foros de Web, donde se plantea la duda de si PHP5 soporta herencia múltiple, lo que termina en una discusión filosófica sobre diseño Orientado a Objetos.

La herencia simple

Es la que tienen todos los lenguajes orientados a objetos: heredamos los atributos de una sola clase padre, lo cual nos permite reutilizar código. Si fuera herencia múltiple, podríamos heredar de más de un padre.

Ejemplo de como se codificaría

La herencia múltiple, si fuera implementada en PHP, se codificaría de la siguiente manera:


class C extends A,B{
// código
}


Donde la clase C hereda atributos y/o métodos de dos clases, A y B.

Por ejemplo, la clase "HombreLobo" puede heredar de la clase "Hombre" y de la clase "Lobo", pero el problema es que se pueden hacer tantas combinaciones que será difícil seguir y mantener un diseño de este tipo. Por eso muchos lenguajes no la implementan, no por un tema técnico, solo por un tema de salvaguardar la integridad del diseño.

¿Se puede hacer o no?

Por lo que he visto en varios lenguajes, la discusión legítima no es "si se puede hacer o no". En muchos casos no se implementa (como en Java, PHP, etc) porque habilitarla es un posible camino al desastre.

Verdaderamente no es problema técnico, o de evolución, es un problema de criterios de diseño "OO".

Herencia múltiple a través de interfaces

De todas formas siempre hay una puerta trasera: hacer herencia múltiple a través de interfaces; pero el sentido es distinto a hacerlo con clases. Las herencias de clases definen el "que son" y las interfaces agrupan clases que definen el "que hacen".

Las interfaces permiten pasar del estilo de diseño "orientado a la implementación" a uno "orientado a la interfaz", donde todas las clases acceden a servicios a través de interfaces que son implementadas por clases concretas. Y al no depender de clases concretas (solo de entidades abstractas) nuestro diseño será más reutilizable que el anterior.

El mayor problema

Los problemas más comunes que puede dar la implementación de herencias múltiples son las "colisiones de nombres" y la "herencia repetida".

Las colisiones se pueden dar cuando las clases empiezan a tener los mismos nombres en los métodos generando la duda de cual método debo usar de las dos clases y la herencia repetida es cuando nuestra clase hereda de dos clases que a sus vez son hijas del mismo padre, por lo cual estemos posiblemente heredando características repetidas.

¿Que sugieren las "Guias de Diseño OO"?

Y ya que estamos del tema "diseño", lo comento: las guías de diseño recomiendan que para una buena jerarquía de herencia:

- Se deben tener no más de 7 (+-2) niveles
- Las jerarquías "gordas y bajas" son síntoma de "poca especialización"
- Las jerarquías "altas y flacas" son síntoma de "excesiva especialización".

¿Si tantas recomendaciones existen para la herencia simple, que queda esperar para la herencia múltiple?

¿Y los grandes libros de Patrones de Diseño?

Hasta yo puedo crear un patrón y usar la herencia múltiple, pero eso no quiere decir que sea la mejor solución a un problema, ni que este pueda aplicarse en otros contextos (la esencia de los patrones).

Tomando como referencia un libro base reconocido mundialmente como es el GOF , donde ninguno de los patrones (de los 23) hacen uso de la herencia múltiple, y tampoco la sugieren, y menos, se quejan de su falta.

Los patrones de diseño son considerados la mejor "receta de cocina" para resolver un problema recurrente, con el mejor diseño posible, donde puede ser aplicado en otros contextos (concepto de patrón: "elemento reutilizable de experiencia y conocimiento").

No he leído hasta el momento en ningún texto que documente principios, sugerencias, guías o buenas prácticas de diseño la recomendación de usar la herencia múltiple. Es más, lo que he visto es todo lo contrario, hacen mucho hincapié en controlar el uso de la herencia simple, llegando a desaconsejar hasta la sobreescritura de los métodos por el hecho de "¿para que heredas si luego sobreescribes el comportamiento?".

Tampoco he leido que exista una discusión importante sobre el tema ni que hubiera una campaña para su uso. Creo que no se discute mucho el hecho de la "no conveniencia" del uso de la herencia múltiple.

Resumen Final

El tema va más allá del lenguaje, el problema no es si un lenguaje lo soporta o no, el problema es si se debe usar o no, y los efectos que pueden causar sobre nuestro diseño y su posterior mantenimiento.

Si observamos la evolución de los lenguajes podremos ver que cada vez se orientan más a seguir las pautas que se dictan en la esfera del diseño, y esto no es para extrañarse, la programación es solo una parte de todo el proceso de desarrollo de software.

Nota al margen: con respecto a mis conclusiones sobre la herencia múltiple, no son de mi exclusiva invención ni se me ocurrieron meditando bajo un manzano... luego de leer muchas opiniones al respecto que apuntaban a tratar el tema como si fuera solo una "evolución", o la visión completamente opuesta, que los nuevos lenguajes "la carecen" (como si estuviéramos hablando de una debilidad) fue que me puse a investigar y a tratar de discernir entre lo subjetivo y lo objetivo.

Y como se concluye en la discusión del foro, los lenguajes son herramientas que se deben ajustar a los criterios de un diseño.

Al final de cuentas, todo es una discusión de diseño OO, aprender a usar una herramienta y a no abusar de las posibilidades de la misma, lo que puede volverla en contra nuestra.

Artículo basado en una discusión originada en Foros del Web

Artículo relacionado

5 comentarios:

Beñat Gurmendi dijo...

Te voy a indicar un libro que defiende la herencia múltiple y la justifica muy bien:

Construcción de Software Orientado a Objetos
de Bertrand Meyer
ISBN 84-8322-040-7

Los problemas que dices que se presentan al permitir la herencia múltiple ("colisiones de nombres" y la "herencia repetida") se solucionan elegantemente permitiendo renombrar los métodos.

Que yo sepa, de los lenguajes que permiten la herencia múltiple, sólo Eiffel permite ofrece el renombrado. Así que es la única implementación de herencia múltiple bien realizada.

El problema de la impopularidad de la herencia múltiple creo que es C++ y lo mal que lo implementa.

La herencia múltiple de interfaz es totalmente necesaria. Por eso muchos lenguajes la proporcionan de una u otra forma. En Java por ejemplo se añaden interfaces.

La herencia múltiple de implementación es muy útil y no tiene problemas si se ofrece la opción de renombrado de métodos. Es útil porque reduce la cantidad de código y de conceptos necesarios. Las interfaces no son necesarias y tampoco hay q mantener dos jerarquías por separado, una para las interfaces y otra para las clases.

enrique_place dijo...

Estimado Beñat:

> Te voy a indicar un libro que
> defiende la herencia múltiple y
> la justifica muy bien:

Hay locos en todos lados, que unos pocos libros hablen del tema no lo valida como una estrategia recomendable (a la fecha no he visto un solo patrón de diseño que siquiera sugiera la idea).

> Los problemas que dices que
> se presentan al permitir la
> herencia múltiple ("colisiones de
> nombres" y la "herencia
> repetida") se solucionan
> elegantemente permitiendo
> renombrar los métodos.

Que tampoco significa que sea el meollo del problema. El mayor problema es que la herencia múltiple desarma los diseños.

Como ya dije en el post:

- Las jerarquías "gordas y bajas" son síntoma de "poca especialización"
- Las jerarquías "altas y flacas" son síntoma de "excesiva especialización".

¿Si tantas recomendaciones existen para la herencia simple, que queda esperar para la herencia múltiple?

Es una estrategia desaconsejada por donde la mires y donde mires.

> Que yo sepa, de los lenguajes
> que permiten la herencia
> múltiple, sólo Eiffel permite
> ofrece el renombrado. Así que es
> la única implementación de
> herencia múltiple bien realizada.

Más a favor del argumento que la herencia múltiple no es aconsejada.

> El problema de la
> impopularidad de la herencia
> múltiple creo que es C++ y lo mal
> que lo implementa.

No le veo la lógica, perfectamente otro lenguaje podría implementarla bien... y?

> La herencia múltiple de
> interfaz es totalmente necesaria.
> Por eso muchos lenguajes la
> proporcionan de una u otra forma.
> En Java por ejemplo se añaden
> interfaces.

La herencia de clases y la herencia de interfaces no tienen nada que ver entre ellas. Son dos conceptos completamente distintos. Generalmente cuando se habla de "herencia múltiple" se refiere a clases, no interfaces. Las interfaces son "contratos de implementación", ni siquiera tiene código, además de agrupar clases por lo que hacen y no por lo que son (no hay "parentesco").

> La herencia múltiple de
> implementación es muy útil y no
> tiene problemas si se ofrece la
> opción de renombrado de métodos.
> Es útil porque reduce la cantidad
> de código y de conceptos
> necesarios.

Herencia va más allá del reuso del código... cuando se hacen diseños pensando en esto es cuando más errores se cometen (Principo de Liskov).

> Las interfaces no son necesarias
> y tampoco hay q mantener dos
> jerarquías por separado, una para
> las interfaces y otra para las
> clases.


Eh?! Te fuiste al infinito disparatado y más allá, la herencia de clases nada tiene que ver con las interfaces, son dos conceptos completamente distintos y no pueden unirse.

Pablo dijo...

"Eh?! Te fuiste al infinito disparatado y más allá, la herencia de clases nada tiene que ver con las interfaces, son dos conceptos completamente distintos y no pueden unirse."

Que copado tener a un blogger que trate asi a sus lectores ;).

Sos el Baby Etchecopar de los blogs.

Santi!# dijo...

>> Te voy a indicar un libro que
>> defiende la herencia múltiple y
>> la justifica muy bien:

> Hay locos en todos lados, que unos > pocos libros hablen del tema no lo > valida como una estrategia recomendable (a la fecha no he visto > un solo patrón de diseño que siquiera sugiera la idea).

Enrique:
Coincido con vos en el tema de la herencia, y en todo lo que expusiste. Pero quería remarcar que el "loco" Bertrand Meyer, un poquito entiende del tema y amerita para que al menos veas que es lo que el dice. Pero igualmente estoy con vos en el tema de la herencia y la implementación de interfaces.

Saludos!

Pablo dijo...

Hola:

Aunque acabo de descubrir tu blog y me parece muy interesante, habría que puntualizar varias cosas.

1-. La herencia múltiple es un mecanismo más de la orientación a objetos, y si se usa bien, bastante potente. Si se usa mal, pues como la herencia simple, molesta más que ayuda.

2-. Bertrand Meyer no es ningún loco o personaje aleatorio, sino uno de los más famosos personajes dentro de la comunidad de la orientación a objetos, primer premio Dahl-Nygaard por la AITO, que no es un premio que se lo den al primero que pasa. Sus opiniones pueden ser o no ciertas, como la de cualquier persona, pero por su trayectoria merecen algo de consideración porque la experiencia nos ha demostrado que sus opiniones suelen ser bastante ciertas.

3-. Gran parte de la investigación actual en programación orientada a objetos versa sobre cosas como mixins, orientación a características, etc. muchas de las cuales se pueden resolver de forma simple y elegante usando herencia múltiple.

Por tanto, la herencia múltiple está ahí y si se usa bien puede ser muy útil. Ahora, hay que saber usarla bien. A mi me da cierta pena que no aparezca en los lenguajes modernos.

Un saludo, Pablo.