ViewHelper可更新/可注入困境 [英] ViewHelper newable/injectable dilemma

查看:109
本文介绍了ViewHelper可更新/可注入困境的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试根据

I'm trying to design an application following Misko Heverys insights. It's an interesting experiment and a challenge. Currently I'm struggling with my ViewHelper implementation.

ViewHelper将模型与视图解耦.在我的实现中,它包装了模型并提供了供视图使用的API.我正在使用PHP,但希望该实现对所有人都可读:

The ViewHelper decouples the model from the view. In my implementation it wraps the model and provides the API for the view to use. I'm using PHP, but I hope the implementation is readable for everyone:

class PostViewHelper {
    private $postModel;

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

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

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

In my template (view) file this could be called like this:

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

到目前为止,一切都很好.我遇到的问题是当我要将过滤器附加到ViewHelpers时.我希望有一些插件可以过滤title()调用的输出.该方法将变成这样:

So far so good. The problem I have is when I want to attach a filter to the ViewHelpers. I want to have plugins that filter the output of the title() call. The method would become like this:

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

我需要在其中放置观察者,EventHandler或任何服务(在我认为是可更新的服务中,因此需要通过堆栈传递).我该如何遵循Misko Hevery的原则?我知道如果没有它我该怎么办.我对该如何使用感兴趣,目前还没有解决方案. ViewHelper也可以是可注射的,但是在那里引入模型是有问题的.

I need to get observers in there, or an EventHandler, or whatever service (in what I see as a newable, so it needs to be passed in through the stack). How can I do this following the principles of Misko Hevery? I know how I can do this without it. I'm interested in how for I can take it and currently I don't see a solution. ViewHelper could be an injectable too, but then getting the model in there is the problem.

推荐答案

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

I didn't find the blog post you referenced very interesting or insightful.

您描述的内容似乎更像是装饰器,而不是与依赖项注入有关的任何东西.依赖注入是构造对象图的方式,而不是构造对象图的状态.

What you are describing seems more like a Decorator than anything to do with dependency injection. Dependency injection is how you construct your object graphs, not their state once constructed.

也就是说,我建议采用您的Decorator模式并运行它.

That said, I'd suggest taking your Decorator pattern and running with it.

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";
    }
}

您只需使用所需的任何DI框架即可构建该对象图,如下所示:

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.

您可能会遇到的一个问题是在PostInterface中定义太多"功能.必须在每个装饰器类中实现它们可能是一个痛苦.我利用PHP的魔术功能解决了这个问题.

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.

这篇关于ViewHelper可更新/可注入困境的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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