Композитный шаблон в PHP, как создавать классы для работы вокруг необходимости расширения двух классов

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

interface Ai1ec_Renderable { /** * This is the main function, it just renders the method for the element, * taking care of childrens ( if any ) */ public function render(); } 

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

 abstract class Ai1ec_Can_Have_Children { /** * * @var array */ protected $renderables = array(); /** * Adds a renderable child to the element * * @param Ai1ec_Renderable $renderable */ public function add_renderable_children( Ai1ec_Renderable $renderable ) { $this->renderables[] = $renderable; } } 

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

 abstract class Ai1ec_Html_Element { /** * * @var string */ protected $id; /** * * @var array */ protected $classes = array(); /** * * @param $id string */ public function set_id( $id ) { $this->id = $id; } public function add_class( $class ) { $this->classes[] = $class; } protected function create_class_markup() { if (empty( $this->classes )) { return ''; } $classes = implode( ' ', $this->classes ); return "class='$classes'"; } protected function create_attribute_markup( $attribute_name, $attribute_value ) { if (empty( $attribute_value )) { return ''; } return "$attribute_name='$attribute_value'"; } } 

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

Я сделал что-то неправильно при разработке моих классов? Как я могу выйти из этого? Самый очевидный способ – сделать класс, дублирующий некоторый код

     abstract class Ai1ec_Can_Have_Children extends Ai1ec_Html_Element { /** * * @var array */ protected $renderables = array(); /** * Adds a renderable child to the element * * @param Ai1ec_Renderable $renderable */ public function add_renderable_children( Ai1ec_Renderable $renderable ) { $this->renderables[] = $renderable; } } 

    это будет работать, но это запах, что что-то не так, поскольку мне нужно будет дублировать код, если я что-то добавлю в Can_Have_Children. Что мне делать?

    PS Нет черт, я поддерживаю 5.2

    Related of "Композитный шаблон в PHP, как создавать классы для работы вокруг необходимости расширения двух классов"

    Кажется, здесь есть две основные обязанности: оказание и наличие детей. Поэтому я бы начал с двух отдельных интерфейсов:

     interface Renderable { public function render(); } interface Container { public function addChild(Renderable $renderable); } 

    Затем выполните конкретную реализацию Container (не абстрактно):

     class BasicContainer implements Container, Renderable { /* similar to your Ai1ec_Can_Have_Children class */ } 

    Затем вы можете определить свои классы элементов HTML следующим образом, используя композицию вместо наследования для добавления функциональности контейнера:

     abstract class HtmlElement implements Renderable { /* similar to your Ai1ec_Html_Element class */ } abstract class ContainerHtmlElement extends HtmlElement implements Container { private $container = new BasicContainer(); public function addChild(Renderable $renderable) { $this->container->addChild($renderable); } public function render() { parent::render(); $this->container->render(); } } 

    Два важных принципа шаблона проектирования можно найти здесь:

    1. Программа для интерфейса, а не для реализации
    2. Использовать композицию объекта над наследованием

    Если вы посмотрите на исходную диаграмму классов в книге GoF, вы увидите, что интерфейс Component имеет две реализации: Leaf и Composite. Участник «Лист» реализует только Операцию (), и никто из других. Например, рассмотрим следующее:

      <?php class Leaf implements IComponent { private $sName; public function __construct($sNodeName) { $this->sName=$sNodeName; } /* None of this batch of methods are used by Leaf */ /* However in order to correctly implement the interface */ /* you need some kind of implementation */ public function add(IComponent $comOn){} public function remove(IComponent $comGone){} public function getChild($someInt){} /* Some userful content is required for the operation */ public function operation() { echo $this->sName . "<br />"; } } ?> 

    Таким образом, хотя участник Leaf в шаблоне реализует только метод operation (), он имеет фиктивные реализации других методов интерфейса. Вы можете найти более подробную информацию по адресу:

    http://www.php5dp.com/the-composite-design-pattern-in-php-part-i-from-conceptual-to-practical/

    а также

    http://www.php5dp.com/category/design-patterns/composite/

    Композит – один из немногих, где вы найдете такое «одно крыло».