2010-05-07 33 views
2

我有一个问题,我一直辛苦了很长一段时间。我正在构建一个模板引擎,主要有两个主类Template.phpTag.php,并附带一系列扩展类,如Img.phpString.php设计模式问题:封装或继承

的程序是这样的:

一个模板对象创建标签对象。每个标签对象确定要实现哪个扩展类(img,string等)。

Tag类的点是为每个扩展类如wrap('div'),addClass('slideshow')提供辅助功能,等等

每个图或String类用于呈现特定于需要什么代码,所以$Img->render()会看到这样的<img src='blah.jpg' />

我的问题是:

嘘乌尔德我标签对象中封装所有的扩展功能,像这样:

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

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

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

有一件事我需要的是用于创建自定义的标签,即可以实例化图(...)的通用接口则实例字符串(...),我做的需要使用Tag实例化每个扩展。

编辑:也只是为了说明:标签类具有所有扩展类通用的功能,Tag类中不应该有任何方法需要在扩展类中实现。标签类仅提供帮助函数。

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

谢谢! Matt Mueller

回答

2

继承将比在单个Tag类中封装不同标记的所有功能更有意义。分离关注点很重要,所以最好在这里采用基于继承的方法。否则,你最终会在一个类中产生一堆不同的标签专用逻辑,这是不好的。这是一个维修噩梦!

如果你有Img特定的逻辑,把它放在它自己的类中。您可以将所有常用方法放在Tag类中。如果这是Java,我会将Tag作为抽象类或者甚至是一个接口,并且具有不同的实现(ImgDiv等)扩展(在抽象类的情况下)或实现(在接口的情况下) 。

一个更好的方法是拥有一个Tag接口,然后是一个实现所有公共逻辑的抽象类。然后,您的特定标签可以实现Tag界面并延伸到AbstractTag。但是,我不知道这在PHP中是否可行,但您可以尝试做类似的事情。

+0

非常感谢您的建议。静态的Tag :: create(...)怎么样是合理的?自从我陷入严重的OOP之后,我已经有一段时间了。也仅仅为了说明:Tag类具有所有扩展类的通用功能,Tag类中不应该有任何需要在扩展类中实现的方法。标签类仅提供帮助函数。 – Matt 2010-05-07 03:54:25

+0

我会做一些像'Img :: create()'。 'AbstractTag'中的构造函数应该是抽象的,所以创建标签的唯一方法就是调用特定于标签的构造函数。你可以这样做,或者在你的'Tag'类中有工厂来创建特定的标签对象。 – 2010-05-07 04:39:39

1

new Tag('img')也没有Tag::create('img')看起来令人信服。我认为,使用标签的决定是在错误的地方 - 标签类中 - 而它明显属于模板。标签及其后代应该无法控制他们将如何使用。

我建议如下:创建标签

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

作为一般性建议,不要以任何代价静态方法。静态属性只是全球功能的别名,没有任何关于它们的面向对象。

+0

很好的建议!我对这种情况的一个问题是Template对createImage(或者insertImage)有特定的调用。我希望模板不知道插件或扩展(img,span)类是否可用。这使得它非常容易扩展。我同意标签的创建应该在模板中。我忘了添加,但新的标签(..)和Tag.create(..)在Template.php中。非常感谢您的写作! – Matt 2010-05-08 02:55:03