复合模式在PHP中,如何设计类来解决需要扩展两个类 [英] Composite pattern in PHP, how to design classes to work around the need to extend two classes

查看:123
本文介绍了复合模式在PHP中,如何设计类来解决需要扩展两个类的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用复合图案有可重用的元素来构建一个页面。对于这个我有一个简单的界面驱动模式

I'm using the composite pattern to have reusable elements to build a page. for this i have a simple interface which drives the pattern

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();
}

因为只有一些元素将允许有孩子,一个添加该行为的抽象类

Since only some of the elements will be allowed to have children, i have created an abstract class that adds that behaviour

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元素

so if the object can have children it extends the abstract class. The problem arise because i have a second abstract class for html elements

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),而不是第二个(这是因为它们是更高级别的抽象,配置另一个可渲染对象来完成该作业),其中一些是第二个而不是第一个

The problem is that all the objects of the composite must implement the interface, some of them must extend only the first class ( can_have_children ) but not the second ( this is because they are higher level abstraction that configure another renderable object to do the job ), some of them the second but not the first and some of them both classes.

在设计我的课程时,我做错了什么?我如何摆脱它?最明显的方法是让一个类重复一些代码

Have i done somthing wrong while designing my classes?How do i come out of it? The most obvious way is to make a class duplicating some code

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。我该怎么办?

this would work, but it's a smell that something is not right, as i would need to duplicate code if i add something to Can_Have_Children. What should i do?

没有traits,我支持5.2

P.S. No traits, i support 5.2

推荐答案

这里似乎有两个主要职责:渲染和有孩子。所以我从两个单独的接口开始:

It seems there are two major responsibilities here: rendering and having children. So I would start with two separate interfaces:

interface Renderable {
  public function render();
}

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

然后具体实现 Container (不抽象):

Then have a concrete implementation of Container (not abstract):

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

然后,您可以如下定义HTML元素类,而不是继承添加容器功能:

Then you can define your HTML element classes as follows, using composition instead of inheritance for adding container functionality:

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();
  }
}

这篇关于复合模式在PHP中,如何设计类来解决需要扩展两个类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆