1

複合パターンを使用して、再利用可能な要素を使用してページを作成しています。このために、パターンを駆動するシンプルなインターフェースがあります

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要素の2番目の抽象クラスがあるため、問題が発生します

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 ) のみを拡張し、2 番目のクラスは拡張しない必要があることです (これは、別のレンダリング可能なオブジェクトを構成してジョブを実行する高レベルの抽象化であるためです)。 、それらのいくつかは2番目であるが最初ではなく、それらのいくつかは両方のクラスです。

クラスの設計中に何か間違ったことをしたことがありますか?どうすれば解決できますか? 最も明白な方法は、いくつかのコードを複製するクラスを作成することです

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 をサポートしています

4

2 に答える 2

3

ここには、レンダリングと子供を持つという2つの主要な責任があるようです。したがって、2 つの別個のインターフェースから始めます。

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();
  }
}
于 2012-08-11T23:49:41.303 に答える
0

2 つの重要なデザイン パターンの原則がここにあります。

  1. 実装ではなくインターフェイスへのプログラム
  2. 継承よりもオブジェクト合成を優先する

GoF ブックの元のクラス図を見ると、Component インターフェイスに Leaf と Composite の 2 つの実装があることがわかります。Leaf 参加者は Operation() のみを実装し、他は実装しません。たとえば、次のことを考慮してください。

    <?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/

Composite は、この種の「片翼」の実装が見られる数少ないものの 1 つです。

于 2014-07-30T12:20:48.013 に答える