Я ищу хороший чистый способ обойти тот факт, что PHP5 по-прежнему не поддерживает множественное наследование. Вот иерархия классов:
Сообщение
- TextMessage
-------- InvitationTextMessage
- EmailMessage
-------- InvitationEmailMessage
У двух типов классов Invitation * много общего; Я бы хотел иметь общий родительский класс, Приглашение, от которого они оба унаследовали бы. К сожалению, у них также много общего со своими нынешними предками ... TextMessage и EmailMessage. Здесь классическая тяга к множественному наследованию.
Какой самый легкий подход к решению проблемы?
Спасибо!
php
oop
inheritance
Алекс Вайнштейн
источник
источник
Ответы:
Алекс, в большинстве случаев множественное наследование является сигналом, что структура вашего объекта несколько неверна. В описанной вами ситуации я вижу, что у вас слишком широкая классовая ответственность. Если сообщение является частью бизнес-модели приложения, оно не должно заботиться о рендеринге вывода. Вместо этого вы можете разделить ответственность и использовать MessageDispatcher, который отправляет сообщение, переданное с использованием текстового или HTML-внутреннего интерфейса. Я не знаю вашего кода, но позвольте мне смоделировать его так:
Таким образом, вы можете добавить некоторую специализацию к классу Message:
Обратите внимание, что MessageDispatcher примет решение, отправлять ли как HTML или простой текст, в зависимости от
type
свойства в переданном объекте сообщения.Подводя итог, можно сказать, что ответственность разделена между двумя классами. Конфигурация сообщения выполняется в классе InvitationHTMLMessage / InvitationTextMessage, а алгоритм отправки делегируется диспетчеру. Это называется паттерном стратегии, вы можете прочитать о нем подробнее здесь .
источник
Tracing
(это всего лишь образец), в котором вы хотите иметь общие вещи, такие как отладка в файл, отправка SMS для критических проблем и так далее. Все ваши классы - дети этого класса. Теперь предположим, что вы хотите создать класс,Exception
который должен иметь эти функции (= дочерний элементTracing
). Этот класс должен быть дочерним по отношению к классуException
. Как создать такой материал без множественного наследования? Да, у вас всегда может быть решение, но вы всегда будете близки к взлому. А взлом = дорогое решение в долгосрочной перспективе. Конец истории.Может быть, вы можете заменить отношение «есть-а» на отношение «имеет-а»? Приглашение может содержать сообщение, но не обязательно, чтобы оно было «есть». Приглашение fe может быть подтверждено, что плохо сочетается с моделью сообщения.
Поищите «композиция против наследования», если вам нужно узнать об этом больше.
источник
Если я могу процитировать Фила в этой ветке ...
И Крис ....
Думаю, у них обоих есть полезные ссылки. Не могу дождаться, чтобы опробовать трейты или, может быть, несколько миксинов ...
источник
В фреймворке Symfony есть плагин миксина для этого , вы можете попробовать его - даже просто для идей, если не использовать его.
Ответ «паттерна проектирования» состоит в том, чтобы выделить общие функции в отдельный компонент и составить их во время выполнения. Подумайте о способе абстрагироваться от функциональности приглашения как класса, который связан с вашими классами сообщений каким-либо образом, кроме наследования.
источник
Я использую трейты в PHP 5.4 как способ решения этой проблемы. http://php.net/manual/en/language.oop5.traits.php
Это позволяет использовать классическое наследование с расширениями, но также дает возможность помещать общие функции и свойства в «признак». Как сказано в руководстве:
источник
Похоже, что шаблон декоратора может быть подходящим, но трудно сказать без дополнительных деталей.
источник
Это и вопрос, и решение ....
А как насчет волшебного _ call (),_get (), __set () методы? Я еще не тестировал это решение, но что, если вы создадите класс multiInherit. Защищенная переменная в дочернем классе может содержать массив наследуемых классов. Конструктор в мультиинтерфейсном классе может создавать экземпляры каждого из наследуемых классов и связывать их с частным свойством, например _ext. Метод __call () может использовать функцию method_exists () для каждого из классов в массиве _ext, чтобы найти правильный метод для вызова. __get () и __set могут использоваться для поиска внутренних свойств, или, если вы эксперт со ссылками, вы можете сделать свойства дочернего класса и унаследованных классов ссылками на одни и те же данные. Множественное наследование вашего объекта будет прозрачным для кода, использующего эти объекты. Также, внутренние объекты могут напрямую обращаться к унаследованным объектам, если это необходимо, если массив _ext индексируется по имени класса. Я задумал создать этот суперкласс, но еще не реализовал его, так как считаю, что если он сработает, это может привести к развитию некоторых плохих привычек программирования.
источник
instanceof
)У меня есть пара вопросов, чтобы прояснить, что вы делаете:
1) Содержит ли ваш объект сообщения просто сообщение, например, тело, получателя, расписание? 2) Что вы собираетесь делать со своим объектом приглашения? Нужно ли рассматривать его отдельно по сравнению с EmailMessage? 3) Если да, то ЧТО в этом особенного? 4) Если это так, то почему типы сообщений для приглашения нужно обрабатывать по-другому? 5) Что делать, если вы хотите отправить приветственное сообщение или сообщение ОК? Это тоже новые объекты?
Похоже, вы пытаетесь объединить слишком много функций в набор объектов, которые должны быть связаны только с хранением содержимого сообщения, а не с тем, как с ним следует обращаться. Как видите, для меня нет разницы между приглашением и стандартным сообщением. Если приглашение требует особой обработки, это означает логику приложения, а не тип сообщения.
Например: система, которую я построил, имела объект общего базового сообщения, который был расширен до SMS, электронной почты и других типов сообщений. Однако: они не были расширены - сообщение-приглашение представляло собой просто заранее определенный текст, который должен был быть отправлен через сообщение типа Электронная почта. Конкретное приложение для приглашения будет касаться проверки и других требований для приглашения. В конце концов, все, что вы хотите сделать, это отправить сообщение X получателю Y, которое должно быть отдельной системой.
источник
Та же проблема, что и у Java. Попробуйте использовать интерфейсы с абстрактными функциями для решения этой проблемы.
источник
PHP поддерживает интерфейсы. Это может быть хорошей ставкой, в зависимости от ваших сценариев использования.
источник
Как насчет класса приглашения прямо под классом сообщений?
Итак, иерархия идет:
Сообщение
--- Приглашение
------ TextMessage
------ EmailMessage
А в классе Invitation добавьте функциональность, которая была в InvitationTextMessage и InvitationEmailMessage.
Я знаю, что приглашение на самом деле не является типом сообщения, это скорее функциональность сообщения. Так что я не уверен, хороший ли это объектно-ориентированный дизайн или нет.
источник