2010-01-15 5 views
4

Я пытаюсь создать приложение, следующее за Misko Heverys insights. Это интересный эксперимент и вызов. В настоящее время я борюсь с моей реализацией ViewHelper.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, или любой другой сервис (в том, что я вижу, как newable, поэтому он должен быть передан через стек). Как я могу это сделать в соответствии с принципами Мишко Хевери? Я знаю, как я могу это сделать без этого. Мне интересно, как я могу это сделать, и в настоящее время я не вижу решения. ViewHelper также может быть инъекционным, но тогда получить модель в этом есть проблема.

+0

Я пробовал то же самое. Вас может заинтересует этот вопрос: http://stackoverflow.com/questions/3117800/dependency-injection-when-the-class-created-also-needs-runtime-values ​​ –

ответ

4

Я не нашел сообщение в блоге, на котором вы ссылались, очень интересно или проницательно.

То, что вы описываете, скорее похоже на Decorator, чем что-либо, что связано с инъекцией зависимости. Зависимость впрыска как вы строите свои графы объекта, а не их состояние после постройки.

Это говорит о том, что я предлагаю взять ваш узор Decorator и работать с ним.

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 рамки вы должны построить этот объект график так:

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

Я часто использую этот подход при создании сложных вложенных объектов.

Одна проблема, с которой вы можете столкнуться, - это определение «слишком много» функций в вашем PostInterface. Это может быть боль, чтобы реализовать их в каждом классе декоратора. Я использую магические функции PHP, чтобы обойти это.

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

Используя этот тип декоратора, я могу выборочно переопределить любой метод, который мне нужен, чтобы обеспечить декорированную функциональность. Все, что я не переопределяю, передается обратно базовому объекту. При сохранении интерфейса базового объекта может возникать множество украшений.

+0

Спасибо, что ответили на hobodave. Однако есть некоторые вещи, которые я не понимаю. 1) он, похоже, не затрагивает проблему получения фильтров в 2) Я не понимаю, почему модели необходимо реализовать интерфейс, который реализует viewHelper. Если это контракт/api, который может использовать вид, я мог бы просто передать модель напрямую. Так что я не вижу, как ваш ответ решает проблему, которую я хотел бы видеть, и что вы делаете из части представления-модели-для-представления, не кажется мне убедительной. – koen

+0

@koen: 1) «Получение их?» Я предполагаю, что вы имеете в виду построение графика объекта. Это будет сделано вами вручную или с использованием любого используемого объекта Factory или DI. Вы не указали какую-либо информацию о том, как работает ваша инфраструктура DI; таким образом, не имея психических способностей, я не могу показать вам, как это сделать. – hobodave

+0

@koen: 2) Вот что такое Декоратор. PostInterface используется объектами, чтобы сказать: «Эй, я чирикаю, гуляю, разговариваю и действую точно так же, как Почта - так относись ко мне, как к одному». Он также позволяет использовать интерфейс в типе, как показано вашими конструкторами. Вы не хотели бы передавать FooObject в свой конструктор PostViewHelper, поэтому вы используете подсказку типа PostInterface. – hobodave