4

我正在尝试按照Misko Heverys 的见解设计一个应用程序。这是一个有趣的实验,也是一个挑战。目前我正在为我的 ViewHelper 实现而苦苦挣扎。

ViewHelper 将模型与视图分离。在我的实现中,它包装模型并提供 API 供视图使用。我正在使用 PHP,但我希望每个人都可以阅读该实现:

class PostViewHelper {
    private $postModel;

    public function __construct(PostModel $postModel) {
         $this->postModel = $postModel;
    }

    public function title() {
         return $this->postModel->getTitle();
    }
}

在我的模板(视图)文件中,可以这样调用:

<h1><?php echo $this->post->title(); ?></h1>

到现在为止还挺好。我遇到的问题是当我想将过滤器附加到 ViewHelpers 时。我想要过滤 title() 调用输出的插件。该方法将变成这样:

public function title() {
    return $this->filter($this->postModel->getTitle());
}

我需要让观察者在那里,或者一个 EventHandler,或者任何服务(在我看来是一个新的,所以它需要通过堆栈传递)。我怎样才能按照 Misko Hevery 的原则做到这一点?我知道没有它我怎么能做到这一点。我对如何接受它很感兴趣,目前我没有看到解决方案。ViewHelper 也可以是可注入的,但是将模型放入其中是个问题。

4

1 回答 1

4

我没有发现您引用的博客文章非常有趣或有见地。

您所描述的似乎更像是一个装饰器,而不是与依赖注入有关的任何东西。依赖注入是构建对象图的方式,而不是构建后的状态

也就是说,我建议采用您的装饰器模式并使用它运行。

interface PostInterface
{
    public function title();
}

class PostModel implements PostInterface
{
    public function title()
    {
        return $this->title;
    }
}

class PostViewHelper implements PostInterface
{
    public function __construct(PostInterface $post)
    {
        $this->post = $post;
    }

    public function title()
    {
        return $this->post->title();
    }
}

class PostFilter implements PostInterface
{
    public function __construct(PostInterface $post)
    {
        $this->post = $post;
    }

    public function title()
    {
        return $this->filter($this->post->title());
    }

    protected function filter($str)
    {
        return "FILTERED:$str";
    }
}

You'd simply use whatever DI framework you have to build this object graph like so:

$post = new PostFilter(new PostViewHelper($model)));

I often use this approach when building complex nested objects.

One problem you might run into is defining "too many" functions in your PostInterface. It can be a pain to have to implement these in every decorator class. I take advantage of the PHP magic functions to get around this.

interface PostInterface
{
    /**
     * Minimal interface. This is the accessor
     * for the unique ID of this Post.
     */
    public function getId();
}


class SomeDecoratedPost implements PostInterface
{
    public function __construct(PostInterface $post)
    {
        $this->_post = $post;
    }

    public function getId()
    {
        return $this->_post->getId();
    }

    /**
     * The following magic functions proxy all 
     * calls back to the decorated Post
     */
    public function __call($name, $arguments)
    {
        return call_user_func_array(array($this->_post, $name), $arguments);
    }

    public function __get($name)
    {
        return $this->_post->get($name);
    }

    public function __set($name, $value)
    {
        $this->_post->__set($name, $value);
    }

    public function __isset($name)
    {
        return $this->_post->__isset($name);
    }

    public function __unset($name)
    {
        $this->_post->__unset($name);
    }
}

With this type of decorator in use, I can selectively override whatever method I need to provide the decorated functionality. Anything I don't override is passed back to the underlying object. Multiple decorations can occur all while maintaining the interface of the underlying object.

于 2010-02-05T18:07:19.943 回答