Множественное наследование в PHP
Я ищу хороший, чистый способ обойти тот факт, что в php5 не поддерживает множественное наследование. Вот иерархия классов:
-- TextMessage
-------- InvitationTextMessage
-- EmailMessage
-------- InvitationEmailMessage
два вида приглашений* классы имеют много общего; я хотел бы иметь общий родительский класс, приглашение, что они оба будут наследовать. К сожалению, они также имеют много общего со своими нынешними предками... TextMessage и EmailMessage. Классическое стремление к множественному наследованию здесь.
какой самый легкий подход к решению проблемы?
спасибо!
11 ответов:
Алекс, в большинстве случаев вам нужно множественное наследование-это сигнал, что ваша структура объекта несколько неверна. В ситуации, которую вы изложили я вижу у вас классовая ответственность просто слишком широка. Если сообщение является частью бизнес-модели приложения, оно не должно заботиться о выводе вывода. Вместо этого вы можете разделить ответственность и использовать MessageDispatcher, который отправляет сообщение, переданное с помощью text или html backend. Я не знаю вашего кода, но позвольте мне имитировать это образом:
$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);
таким образом, вы можете добавить некоторую специализацию в класс сообщений:
$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);
обратите внимание, что MessageDispatcher будет принимать решение о том, отправлять ли HTML или обычный текст в зависимости от
type
свойство в переданном объекте сообщения.// 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"); } }
подводя итог, ответственность разделена между двумя классами. Конфигурация сообщения выполняется в классе InvitationHTMLMessage/InvitationTextMessage, а алгоритм отправки делегируется диспетчеру. Это называется Шаблон стратегии, вы можете прочитать больше об этом здесь.
может быть, вы можете заменить отношение "есть-а" на отношение "имеет-а"? Приглашение может содержать сообщение, но оно не обязательно должно быть сообщением "is-a". Приглашение f. e.может быть подтверждено, что не очень хорошо сочетается с моделью сообщений.
Поиск 'композиция и наследование, если вам нужно знать больше об этом.
Если я могу процитировать Фила в этой теме...
PHP, как и Java, не поддерживает множественное наследование.
приходя в PHP 5.4 будет черт которые пытаются обеспечить решение к этой проблеме.
в то же время, вам было бы лучше переосмыслить свой дизайн класса. Вы можно реализовать несколько интерфейсов, если вы после расширенного API для ваш класс.
и Крис....
в PHP не поддерживает множественное наследование, но есть некоторые (несколько грязные) способы его реализации. Проверьте этот URL для некоторых примеры:
http://www.jasny.net/articles/how-i-php-multiple-inheritance/
думал, что у них обоих есть полезные ссылки. Не могу дождаться, чтобы попробовать черты или, может быть, некоторые миксины...
структура Symfony имеет mixin плагин для этого, вы можете проверить его-даже просто для идей, если не использовать его.
ответ "шаблон проектирования" заключается в том, чтобы абстрагировать общую функциональность в отдельный компонент и составлять во время выполнения. Подумайте о том, как абстрагировать функциональность приглашения как класс, который связан с вашими классами сообщений каким-либо другим способом, кроме наследования.
звучит как шаблон "декоратор" может быть любой, но трудно сказать без более подробной информации.
Это и вопрос, и решение....
а как насчет волшебного _звоните(),_get (), __set () методы? Я еще не тестировал это решение, но что, если вы создадите класс с несколькими наследствами. Защищенная переменная в дочернем классе может содержать массив классов для наследования. Конструктор в классе multi-interface может создавать экземпляры каждого из наследуемых классов и связывать их с частным свойством, например _ext. Метод __call() может использовать функция method_exists () для каждого из классов в массиве _ext позволяет найти правильный метод для вызова. __get () и __set могут использоваться для поиска внутренних свойств, или если ваш эксперт со ссылками вы можете сделать свойства дочернего класса и наследуемых классов ссылками на одни и те же данные. Множественное наследование объекта будет прозрачным для кода, использующего эти объекты. Кроме того, внутренние объекты могут обращаться к унаследованным объектам напрямую, если это необходимо _ext массив индексируется по имени класса. Я предполагал создать этот супер-класс и еще не реализовал его, поскольку я чувствую, что если он работает, то это может привести к развитию некоторых плохих привычек программирования.
Я использую трейты в PHP 5.4 как способ решения этой. http://php.net/manual/en/language.oop5.traits.php
Это позволяет классическое наследование с расширениями, но также дает возможность размещения общих функций и свойств в "черте". Как говорится в руководстве:
Traits-это механизм повторного использования кода в отдельных языках наследования, таких как PHP. Признак предназначен для уменьшения некоторых ограничений одиночного наследования путем позволяя разработчику повторно использовать наборы методов свободно, в нескольких независимых классах, живущих в разных иерархий классов.
У меня есть пара вопросов, чтобы уточнить, что вы делаете:
1) делает ли ваше сообщение объект просто содержат сообщение, например, тело, получатель, расписание времени? 2) Что вы собираетесь делать с вашим объектом приглашения? Нужно ли его лечить специально по сравнению с электронной почтой? 3) Если да, то что в этом такого особенного? 4) Если это так, то почему типы сообщений должны обрабатываться по-разному для приглашения? 5) Что делать, если вы хотите отправить добро пожаловать сообщение или сообщение ОК? Они тоже новые объекты?
похоже, что вы пытаетесь объединить слишком много функций в набор объектов, которые должны быть связаны только с содержанием сообщения, а не с тем, как его следует обрабатывать. Для меня, видите ли, нет разницы между приглашением или стандартным сообщением. Если приглашение требует специальной обработки, то это означает логику приложения, а не тип сообщения.
например: система, которую я построил, имела общий базовый объект сообщения, который был расширен в SMS, электронную почту и другие типы сообщений. Однако: они не были расширены дальше-приглашение сообщение было просто заранее определенный текст, который будет отправлен через сообщение типа электронной почты. Конкретная заявка на приглашение будет касаться проверки и других требований к приглашению. В конце концов, все, что вы хотите сделать, это отправить сообщение X получателю Y, который должен быть дискретной системой сам по себе.
такая же проблема, как Java. Попробуйте использовать интерфейсы с абстрактными функциями для решения этой проблемы
PHP поддерживает интерфейсы. Это может быть хорошая ставка, в зависимости от ваших вариантов использования.
Как насчет класса приглашения прямо под классом сообщения?
иерархия идет так:
--- Приглашение
------ TextMessage
------ EmailMessageи в классе приглашения добавьте функциональность, которая была в InvitationTextMessage и InvitationEmailMessage.
Я знаю, что приглашение на самом деле не тип сообщения, это скорее функциональность сообщения. Поэтому я не уверен, что это хороший дизайн OO или нет.