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