Pregunta

Estoy buscando una manera buena y limpia de evitar el hecho de que PHP5 todavía no admite herencia múltiple.Aquí está la jerarquía de clases:

Mensaje
-- Mensaje de texto
-------- Mensaje de texto de invitación
-- Mensaje de correo electrónico
-------- Mensaje de correo electrónico de invitación

Los dos tipos de clases por invitación* tienen mucho en común;Me encantaría tener una clase principal común, Invitación, de la que ambos heredarían.Desafortunadamente, también tienen mucho en común con sus antepasados ​​actuales...Mensaje de texto y mensaje de correo electrónico.Aquí el deseo clásico de herencia múltiple.

¿Cuál es el enfoque más ligero para resolver el problema?

¡Gracias!

¿Fue útil?

Solución

Alex, la mayoría de las veces que necesitas herencia múltiple es una señal de que la estructura de tu objeto es algo incorrecta.En la situación que usted describió, veo que su responsabilidad de clase es simplemente demasiado amplia.Si Message es parte del modelo de negocio de la aplicación, no debería preocuparse por generar resultados.En su lugar, puede dividir la responsabilidad y utilizar MessageDispatcher que envía el mensaje pasado utilizando texto o html backend.No conozco tu código, pero déjame simularlo de esta manera:

$m = new Message();
$m->type = 'text/html';
$m->from = 'John Doe <jdoe@yahoo.com>';
$m->to = 'Random Hacker <rh@gmail.com>';
$m->subject = 'Invitation email';
$m->importBody('invitation.html');

$d = new MessageDispatcher();
$d->dispatch($m);

De esta manera puedes agregar alguna especialización a la clase Mensaje:

$htmlIM = new InvitationHTMLMessage(); // html type, subject and body configuration in constructor
$textIM = new InvitationTextMessage(); // text type, subject and body configuration in constructor

$d = new MessageDispatcher();
$d->dispatch($htmlIM);
$d->dispatch($textIM);

Tenga en cuenta que MessageDispatcher tomará la decisión de enviar como HTML o texto sin formato dependiendo de type propiedad en el objeto Mensaje pasada.

// in MessageDispatcher class
public function dispatch(Message $m) {
    if ($m->type == 'text/plain') {
        $this->sendAsText($m);
    } elseif ($m->type == 'text/html') {
        $this->sendAsHTML($m);
    } else {
        throw new Exception("MIME type {$m->type} not supported");
    }
}

En resumen, la responsabilidad se divide entre dos clases.La configuración del mensaje se realiza en la clase InvitationHTMLMessage/InvitationTextMessage y el algoritmo de envío se delega al despachador.Esto se llama Patrón de estrategia, puedes leer más sobre él. aquí.

Otros consejos

¿Quizás puedas reemplazar una relación 'es-un' con una relación 'tiene-un'?Una invitación puede tener un mensaje, pero no necesariamente tiene que ser un mensaje.Una invitación f.e.podría confirmarse, lo que no va bien con el modelo Message.

Busque 'composicion vs.herencia' si necesita saber más sobre eso.

Si puedo citar a Phil en este hilo...

PHP, al igual que Java, no admite herencia múltiple.

Próximamente en PHP 5.4 será rasgos que intentan proporcionar una solución a este problema.

Mientras tanto, lo mejor sería reconsiderar el diseño de su clase.Puede implementar múltiples interfaces si busca una API extendida para sus clases.

Y Cris....

PHP realmente no admite la herencia múltiple, pero hay algunas formas (algo desordenadas) de implementarla.Echa un vistazo a esta URL para obtener algunos ejemplos:

http://www.jasny.net/articles/how-i-php-multiple-inheritance/

Pensé que ambos tenían enlaces útiles.No puedo esperar para probar rasgos o tal vez algunas combinaciones...

El marco Symfony tiene una complemento mixin para esto, es posible que desees consultarlo, aunque solo sea para obtener ideas, si no para usarlo.

La respuesta del "patrón de diseño" es abstraer la funcionalidad compartida en un componente separado y componerla en tiempo de ejecución.Piense en una manera de abstraer la funcionalidad de Invitación como una clase que se asocie con sus clases de Mensaje de alguna manera distinta a la herencia.

Estoy usando rasgos en PHP 5.4 como forma de resolver esto.http://php.net/manual/en/language.oop5.traits.php

Esto permite la herencia clásica con extensiones, pero también ofrece la posibilidad de colocar funcionalidades y propiedades comunes en un "rasgo".Como dice el manual:

Traits es un mecanismo para la reutilización de código en lenguajes de herencia única como PHP.Un rasgo pretende reducir algunas limitaciones de la herencia única al permitir que un desarrollador reutilice conjuntos de métodos libremente en varias clases independientes que viven en diferentes jerarquías de clases.

Suena como el patrón decorador Puede ser adecuado, pero es difícil saberlo sin más detalles.

Esta es a la vez una pregunta y una solución....

¿Qué pasa con el mágico _llamar(),¿Métodos _get(), __set()?Todavía no he probado esta solución, pero ¿qué pasa si crea una clase multiInherit?Una variable protegida en una clase secundaria podría contener una serie de clases para heredar.El constructor de la clase de interfaz múltiple podría crear instancias de cada una de las clases que se heredan y vincularlas a una propiedad privada, por ejemplo _ext.El método __call() podría usar la función Method_exists() en cada una de las clases en la matriz _ext para localizar el método correcto para llamar.__get() y __set podrían usarse para localizar propiedades internas, o si eres un experto en referencias, podrías hacer que las propiedades de la clase secundaria y las clases heredadas sean referencias a los mismos datos.La herencia múltiple de su objeto sería transparente para el código que utiliza esos objetos.Además, los objetos internos podrían acceder a los objetos heredados directamente si fuera necesario, siempre que la matriz _ext esté indexada por nombre de clase.He imaginado la creación de esta superclase y aún no la he implementado porque creo que si funciona, podría llevar al desarrollo de algunos malos hábitos de programación.

Tengo un par de preguntas que hacer para aclarar lo que estás haciendo:

1) ¿Su mensaje se opone? justo contener un mensaje, p.e.cuerpo, destinatario, horario?2) ¿Qué piensas hacer con tu objeto Invitación?¿Es necesario tratarlo de manera especial en comparación con un mensaje de correo electrónico?3) Si es así, ¿QUÉ tiene de especial?4) Si ese es el caso, ¿por qué los tipos de mensajes deben manejarse de manera diferente para una invitación?5) ¿Qué sucede si desea enviar un mensaje de bienvenida o un mensaje de aprobación?¿Son objetos nuevos también?

Parece que está intentando combinar demasiadas funciones en un conjunto de objetos que solo deberían preocuparse por contener el contenido de un mensaje, y no por cómo debe manejarse.Para mí, como ve, no hay diferencia entre una invitación o un mensaje estándar.Si la invitación requiere un manejo especial, eso significa lógica de aplicación y no un tipo de mensaje.

Por ejemplo:Un sistema que construí tenía un objeto de mensaje base compartido que se extendía a SMS, correo electrónico y otros tipos de mensajes.Sin embargo:estos no se ampliaron más: un mensaje de invitación era simplemente un texto predefinido que se enviaba a través de un mensaje de tipo Correo electrónico.Una solicitud de invitación específica se ocuparía de la validación y otros requisitos para una invitación.Después de todo, todo lo que desea hacer es enviar el mensaje X al destinatario Y, que debería ser un sistema discreto por derecho propio.

El mismo problema que Java.Intente usar interfaces con funciones abstractas para resolver ese problema.

PHP admite interfaces.Esta podría ser una buena apuesta, dependiendo de sus casos de uso.

¿Qué tal una clase de Invitación justo debajo de la clase de Mensaje?

entonces la jerarquía va:

Mensaje
--- Invitación
------ Mensaje de texto
------ Mensaje de correo electrónico

Y en la clase Invitación, agregue la funcionalidad que estaba en InvitationTextMessage e InvitationEmailMessage.

Sé que la Invitación no es realmente un tipo de Mensaje, es más bien una funcionalidad del Mensaje.Entonces no estoy seguro de si este es un buen diseño OO o no.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top