Вопрос

Я ищу хороший, чистый способ обойти тот факт, что PHP5 по-прежнему не поддерживает множественное наследование.Вот иерархия классов:

Сообщение
-- Текстовое сообщение
-------- Текстовое сообщение с приглашением
-- Сообщение по электронной почте
-------- Приглашение в почтовое сообщение

Два типа приглашений * на занятия имеют много общего;я бы хотел иметь общий родительский класс Invitation, от которого они оба унаследовали бы.К сожалению, у них также есть много общего со своими нынешними предками...Текстовые сообщения и сообщения электронной почты.Классическое стремление к множественному наследованию здесь.

Какой наиболее легкий подход к решению этой проблемы?

Спасибо!

Это было полезно?

Решение

Алекс, в большинстве случаев, когда вам требуется множественное наследование, это сигнал о том, что структура вашего объекта несколько неверна.В ситуации, которую вы обрисовали, я вижу, что ваша классовая ответственность просто слишком широка.Если сообщение является частью бизнес-модели приложения, оно не должно заботиться о рендеринге выходных данных.Вместо этого вы могли бы разделить ответственность и использовать MessageDispatcher, который отправляет сообщение, переданное с использованием текстового или html-сервера.Я не знаю вашего кода, но позвольте мне смоделировать это таким образом:

$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);

Таким образом, вы можете добавить некоторую специализацию к классу 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, а алгоритм отправки делегируется диспетчеру.Это называется Стратегическим шаблоном, вы можете прочитать о нем подробнее здесь.

Другие советы

Может быть, вы можете заменить отношение "is-a" отношением "has-a"?Приглашение может содержать сообщение, но оно не обязательно должно содержать сообщение "is-a".Приглашение, например.может быть подтверждено, что не очень хорошо сочетается с моделью сообщений.

Поиск по запросу "композиция противнаследование", если вам нужно знать об этом больше.

Если я могу процитировать Фила в этот поток...

PHP, как и Java, не поддерживает множественное наследование.

При переходе на PHP 5.4 будет Трейты которые пытаются обеспечить решение этой проблемы.

А пока вам было бы лучше переосмыслить дизайн вашего класса.Вы можете реализовать несколько интерфейсов, если вам нужен расширенный API для ваших классов.

И Крис....

PHP на самом деле не поддерживает множественное наследование, но есть несколько (несколько запутанных) способов его реализации.Ознакомьтесь с этим URL для получения некоторых примеров:

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

Думал, у них обоих есть полезные ссылки.Не могу дождаться, когда попробую черты характера или, может быть, какие-нибудь миксины...

Фреймворк Symfony имеет плагин mixin для этого, Возможно, вы захотите проверить это - даже просто ради идей, если не для того, чтобы использовать.

Ответ "шаблона проектирования" заключается в том, чтобы абстрагировать общую функциональность в отдельный компонент и создавать во время выполнения.Подумайте о способе абстрагирования функциональности приглашения в виде класса, который будет связан с вашими классами сообщений каким-либо иным способом, кроме наследования.

Я использую черты в PHP 5.4 как способ решения этой проблемы.http://php.net/manual/en/language.oop5.traits.php

Это допускает классическое наследование с расширениями, но также дает возможность поместить общие функциональные возможности и свойства в "признак".Как сказано в руководстве:

Traits - это механизм повторного использования кода в отдельных языках наследования, таких как PHP.Признак предназначен для уменьшения некоторых ограничений одиночного наследования, позволяя разработчику свободно использовать наборы методов в нескольких независимых классах, живущих в разных иерархиях классов.

Это звучит как шаблон декоратора может быть, это и подходит, но трудно сказать без более подробной информации.

Это одновременно и вопрос, и решение....

А как насчет волшебного _вызов (),методы _get(), __set()?Я еще не тестировал это решение, но что, если вы создадите класс с несколькими наследиями?Защищенная переменная в дочернем классе может содержать массив классов для наследования.Конструктор в классе с несколькими интерфейсами может создавать экземпляры каждого из наследуемых классов и связывать их с частным свойством, скажем _ext .Метод __call() может использовать функцию method_exists() для каждого из классов в массиве _ext, чтобы найти правильный метод для вызова.__get() и __set можно использовать для поиска внутренних свойств, или, если вы специалист по ссылкам, вы могли бы сделать свойства дочернего класса и унаследованных классов ссылками на одни и те же данные.Множественное наследование вашего объекта было бы прозрачным для кода, использующего эти объекты.Кроме того, внутренние объекты могут обращаться к унаследованным объектам напрямую, если это необходимо, при условии, что массив _ext индексируется по имени класса.Я предполагал создать этот суперкласс, но еще не реализовал его, поскольку чувствую, что если это сработает, то это может привести к развитию некоторых вредных привычек программирования.

У меня есть пара вопросов, которые я хотел бы задать, чтобы прояснить, что вы делаете:

1) Вызывает ли возражение ваше сообщение просто содержать сообщение, напримертело, получатель, запланированное время?2) Что вы намерены делать со своим объектом Приглашения?Нужно ли к нему относиться особенным образом по сравнению с электронным сообщением?3) Если да, то ЧТО в этом такого особенного?4) Если это так, то почему типы сообщений требуют разной обработки для приглашения?5) Что делать, если вы хотите отправить приветственное сообщение или сообщение "ОК"?Это тоже новые объекты?

Похоже, вы пытаетесь объединить слишком много функциональности в набор объектов, которые должны быть связаны только с хранением содержимого сообщения, а не с тем, как с ним следует обращаться.Видите ли, для меня нет разницы между приглашением или стандартным сообщением.Если приглашение требует специальной обработки, то это означает логику приложения, а не тип сообщения.

Например:система, которую я создал, имела общий базовый объект message, который был расширен на SMS, электронную почту и другие типы сообщений.Однако:они не были расширены дальше - пригласительное сообщение представляло собой просто заранее определенный текст, который должен был быть отправлен через сообщение типа Email.Конкретная заявка на приглашение будет касаться проверки подлинности и других требований к приглашению.В конце концов, все, что вы хотите сделать, это отправить сообщение X получателю Y, которое само по себе должно быть дискретной системой.

Та же проблема, что и с Java.Попробуйте использовать интерфейсы с абстрактными функциями для решения этой проблемы

PHP действительно поддерживает интерфейсы.Это может быть хорошей ставкой, в зависимости от ваших вариантов использования.

Как насчет класса Invitation прямо под классом Message?

итак , иерархия такова:

Сообщение
--- Приглашение
------ Текстовое сообщение
------ Сообщение по электронной почте

И в классе Invitation добавьте функциональность, которая была в InvitationTextMessage и InvitationEmailMessage.

Я знаю, что Приглашение на самом деле - это не тип сообщения, это скорее функциональность Сообщения.Так что я не уверен, хороший это OO-дизайн или нет.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top