php - doble - herencia multiple diamante
Herencia múltiple en PHP (11)
¿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 y InvitationEmailMessage.
Sé que Invitación no es realmente un tipo de Mensaje, es más una funcionalidad de Mensaje. Entonces no estoy seguro de si este es un buen diseño OO o no.
Estoy buscando una forma 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
-------- InvitationTextMessage
-- Mensaje de correo electrónico
-------- InvitaciónEmailMensaje
Los dos tipos de clases de Invitación * tienen mucho en común; Me encantaría tener una clase común para padres, Invitación, de la que ambos heredarían. Desafortunadamente, también tienen mucho en común con sus antepasados actuales ... TextMessage y EmailMessage. Deseo clásico de herencia múltiple aquí.
¿Cuál es el enfoque más ligero para resolver el problema?
¡Gracias!
¿Quizás puedas reemplazar una relación ''es-a'' por una relación ''tiene-a''? Una invitación puede tener un mensaje, pero no necesariamente es un mensaje ''es-a''. Es posible que se confirme una Invitación fe, lo que no va bien junto con el modelo de Mensaje.
Busca "composición vs. herencia" si necesitas saber más sobre eso.
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 describiste, veo que tienes una responsabilidad de clase simplemente demasiado amplia. Si Message forma parte del modelo comercial de la aplicación, no debería preocuparse por generar resultados. En su lugar, puede dividir la responsabilidad y usar MessageDispatcher que envía el mensaje pasado usando texto o back-end html. No conozco tu código, pero déjame simularlo de esta manera:
$m = new Message();
$m->type = ''text/html'';
$m->from = ''John Doe <[email protected]>'';
$m->to = ''Random Hacker <[email protected]>'';
$m->subject = ''Invitation email'';
$m->importBody(''invitation.html'');
$d = new MessageDispatcher();
$d->dispatch($m);
De esta forma, puede agregar cierta especialización a la clase de 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ía la decisión de enviar como HTML o texto sin formato según la propiedad del type
en el objeto Message pasado.
// 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");
}
}
Para resumir, 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 here .
El marco de Symfony tiene un plugin de mixin para esto , es posible que desee verificarlo, incluso para ideas, si no para usarlo.
La respuesta del "patrón de diseño" es abstraer la funcionalidad compartida en un componente separado y componer en tiempo de ejecución. Piense en una forma de abstraer la funcionalidad de Invitación como una clase que se asocia con sus clases de Mensaje de una forma distinta a la herencia.
Esta es una pregunta y una solución ...
¿Y los métodos mágicos _ call (), _get (), __set ()? Todavía no he probado esta solución, pero ¿y si haces una clase multiInherit? Una variable protegida en una clase secundaria podría contener una matriz 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 su experto con referencias podría hacer que las propiedades de la clase hija y las clases heredadas sean referencias a los mismos datos. La herencia múltiple de su objeto sería transparente para codificar usando esos objetos. Además, los objetos internos podrían acceder directamente a los objetos heredados si fuera necesario, siempre que la matriz _ext esté indexada por nombre de clase. He imaginado crear esta superclase y aún no la he implementado, ya que creo que, si funciona, podría generar algunos hábitos de programación diferentes.
Estoy usando rasgos en PHP 5.4 como la forma de resolver esto. http://php.net/manual/en/language.oop5.traits.php
Esto permite la herencia clásica con extends, pero también da la posibilidad de colocar funcionalidades y propiedades comunes en un ''rasgo''. Como dice el manual:
Rasgos es un mecanismo para la reutilización de código en lenguajes de herencia únicos como PHP. Un Rasgo tiene la intención de reducir algunas limitaciones de la herencia individual al permitir que un desarrollador reutilice conjuntos de métodos libremente en varias clases independientes que viven en diferentes jerarquías de clases.
Mismo problema como Java. Intenta usar interfaces con funciones abstractas para resolver ese problema
PHP no admite interfaces. Esta podría ser una buena apuesta, dependiendo de sus casos de uso.
Si puedo citar a Phil en este hilo ...
PHP, como Java, no admite herencia múltiple.
Próximamente en PHP 5.4 serán traits que intentarán proporcionar una solución a este problema.
Mientras tanto, será mejor que reconsideres el diseño de tu clase. Puedes implementar múltiples interfaces si buscas una API extendida para tus clases.
Y Chris ...
PHP realmente no es compatible con herencia múltiple, pero hay algunas formas (un tanto complicadas) de implementarlo. Echa un vistazo a esta URL para ver algunos ejemplos:
http://www.jasny.net/articles/how-i-php-multiple-inheritance/
Pensó que ambos tenían enlaces útiles. No puedo esperar para probar los rasgos o tal vez algunos mixins ...
Tengo un par de preguntas para aclarar lo que estás haciendo:
1) ¿Su objeto de mensaje solo contiene un mensaje, por ejemplo, cuerpo, destinatario, horario de programación? 2) ¿Qué piensas hacer con tu objeto Invitación? ¿Necesita ser tratado especialmente en comparación con un mensaje de correo electrónico? 3) Si es así ¿QUÉ es tan especial al respecto? 4) Si ese es el caso, ¿por qué los tipos de mensaje necesitan un manejo diferente para una invitación? 5) ¿Qué sucede si desea enviar un mensaje de bienvenida o un mensaje de OK? ¿Son nuevos objetos también?
Suena como si estuvieras intentando combinar demasiada funcionalidad en un conjunto de objetos que solo deberían preocuparse por mantener contenidos de un mensaje, y no cómo deberían manejarse. Para mí, como ves, 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 la aplicación y no un tipo de mensaje.
Por ejemplo: un sistema que construí tenía un objeto de mensaje base compartido que se extendió 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 texto predefinido que se enviará a través de un mensaje de tipo Correo electrónico. Una aplicación de invitación específica estaría relacionada con 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.