设计模式问题:封装或继承

时间:2010-05-07 03:37:24

标签: php design-patterns templates

我有一个问题,我已经工作了很长一段时间。我正在构建一个包含两个主要类Template.phpTag.php的模板引擎,以及一些扩展类,如Img.phpString.php

该计划的工作方式如下:

Template对象创建Tag对象。每个标记对象确定要实现的扩展类(img,string等)。

标记类的目的是为每个扩展类提供帮助函数,例如wrap('div'), addClass('slideshow')等。

每个 Img或String类用于呈现特定于所需内容的代码,因此$Img->render()会提供类似<img src='blah.jpg' />

的内容

我的问题是:

我应该封装 Tag对象中的所有扩展功能,如下所示:

Tag.php

function __construct($namespace, $args) {
    // Sort out namespace to determine which extension to call
    $this->extension = new $namespace($this); // Pass in Tag object so it can be used within extension

    return $this; // Tag object
}

function render() {
    return $this->extension->render();
}

Img.php

    function __construct(Tag $T) {
        $args = $T->getArgs();
        $T->addClass('img');
    }

    function render() {
        return '<img src="blah.jpg" />';
    }

用法:

$T = new Tag("img", array(...);
$T->render();

....或者我应该创建更多的继承结构,因为“Img是一个标签”

Tag.php

public static create($namespace, $args) {
    // Sort out namespace to determine which extension to call
    return new $namespace($args);

}

Img.php

class Img extends Tag {
    function __construct($args) {
        // Determine namespace then call create tag
        $T = parent::__construct($namespace, $args);
    }

    function render() {
        return '<img src="blah.jpg" />';
    }
}

用法:

$Img = Tag::create('img', array(...));
$Img->render();

我需要的一件事是创建自定义标签的通用界面,即我可以实例化Img(...)然后实例化String(...),我需要使用Tag实例化每个扩展。

编辑:另外只是为了澄清:Tag类具有所有扩展类共有的功能,Tag类中不应该有任何需要在扩展类中实现的方法。 Tag类仅提供辅助函数。

我知道这个问题有点模糊,我希望你们中的一些人过去曾经处理过这个问题,并且可以预见选择每种设计模式时会遇到一些问题。如果您有任何其他建议,我很乐意听到。

谢谢! 马特穆勒

2 个答案:

答案 0 :(得分:2)

继承比在单个Tag类中封装不同标记的所有功能更有意义。关注点分离很重要,因此最好采用基于继承的方法。否则,你最终会在一个类中拥有一堆不同的特定于标签的逻辑,这很糟糕。这是一场维护噩梦!

如果您有Img特定的逻辑,请将其放在自己的类中。您可以将所有常用方法放在Tag类中。如果这是Java,我会将Tag作为抽象类甚至是接口,并使不同的实现(ImgDiv等)扩展(在摘要的情况下) class)或实现(在接口的情况下)。

更好的方法是拥有一个Tag接口,然后是一个实现所有通用逻辑的AbstractTag抽象类。然后,您的特定代码可以实现Tag界面并扩展AbstractTag。但是,我不知道这在PHP中是否完全可行,但你可以尝试做类似的事情。

答案 1 :(得分:1)

new Tag('img')Tag::create('img')都不能令我信服。我认为,决定使用哪个标签是在错误的地方 - 在Tag类中 - 虽然它明显属于模板。标签及其后代应该无法控制它们的使用方式。

我建议如下:创建标签的层​​次结构

 abstract class Tag { ...common methods.... }
 class ImgTag extends Tag { ...image specific methods... }
 class SpanTag extends Tag { ...image specific methods... }

并且在模板中只需在需要时使用新的WhateverTag

 class Template...
    function insertImage
      $tag = new ImgTag($atts);
      $tag->render();

如果标签是在多个地方创建的,那么最好有一个工厂方法,但它仍然属于模板

 class Template...
    function createImage
      return new ImgTag($atts);

    function insertOneImage
      $tag = $this->createImage
      $tag->render();

    function insertAnotherImage
      $tag = $this->createImage
      $tag->render();

作为一般建议,不惜任何代价避免使用静态方法。静态只是全局函数的花哨别名,没有任何面向对象的。