Статьи

Практические шаблоны PHP: посредник


Паттерн дня —
Медиатор . Цель этого шаблона заключается в инкапсуляции взаимодействий набора объектов, предотвращая агрессивную связь между каждым из них и другими.
Посредник выступает в качестве центральной точки сходимости между
КОЛЛЕГОЙ объектами.

В любом домене есть много операций, которые не подходят для существующих объектов, смоделированных из реальности, и если их принудительно использовать как методы уже существующего класса, это добавит зависимость к возможно не связанному сотруднику. Такой подход приведет к созданию сети
тесно взаимосвязанных объектов Colleague, а не к
коду Ravioli.мы хотим работать с Объекты «Коллеги» должны быть слабо связаны, чтобы избежать необходимости ссылаться на них в целом в любое время, когда один из них требуется от Клиента.

Решение этой распространенной проблемы заключается в реализации шаблона посредника. Когда отношения объекта и зависимости начинают конфликтовать с его деловой ответственностью (причина, по которой он был создан в первую очередь), мы должны ввести посредника, который
координирует рабочий процесс между связанными объектами, освобождая их от этой формы связи; могут быть установлены зависимости от Коллег по отношению к Посреднику и / или от Посредника по отношению к Коллегам. Оба направления этих зависимостей могут быть нарушены с помощью интерфейса
AbstractColleague или
AbstractMediator, если необходимо.

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

В качестве практического примера, Услуги в
доменно-управляемом дизайне являются посредниками между сущностями. Для
php- связанного примера
Zend_FormВозможности декорирования и фильтрации на самом деле являются реализацией простого посредника между экземплярами Zend_Form_Decorator и Zend_Filter. То же самое касается проверки с использованием объектов Zend_Validate. Создание каждого фильтра со ссылкой на следующий создаст
цепочку ответственности, потенциал которой не будет использован.

Когда Посредник должен прослушивать события Коллеги, он часто реализуется как Наблюдатель, в результате чего создается
объект классной доски, на котором одни Коллеги пишут, а другие читают. События передаются Посреднику от Коллеги, прежде чем он доставляет их другим подписавшимся Коллегам. Никто из них не знает других коллег: эта архитектура успешно используется в
ДодзёБиблиотека JavaScript поставляется с Zend Framework.

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

участники

  • Коллега : фокусируется на своей ответственности, общаясь только с Посредником или Абстрактным Медиатором.
  • Посредник : координирует работу набора, составленного несколькими Коллегами (AbstractColleagues).
  • AbstractMediator , AbstractColleague : дополнительные интерфейсы, которые отделены от фактической реализации этих ролей. Может быть более одной роли AbstractColleague.

Пример кода реализует процесс фильтрации для ввода формы, который напоминает функцию Zend_Form_Element.

<?php
/**
* AbstractColleague.
*/
interface Filter
{
public function filter($value);
}

/**
* Colleague. We decide in the implementation phase
* that Colleagues should not know the next Colleague
* in the chain, resorting to a Mediator to link them together.
* This choice succesfully avoids a base abstract class
* for Filters.
* Remember that this is an example: it is not only
* Chain of Responsibility that can be alternatively implemented
* as a Mediator.
*/
class TrimFilter implements Filter
{
public function filter($value)
{
return trim($value);
}
}

/**
* Colleague.
*/
class NullFilter implements Filter
{
public function filter($value)
{
return $value ? $value : '';
}
}

/**
* Colleague.
*/
class HtmlEntitiesFilter implements Filter
{
public function filter($value)
{
return htmlentities($value);
}
}

/**
* The Mediator. We avoid referencing it from ConcreteColleagues
* and so the need for an interface. We leave the implementation
* of a bidirectional channel for the Observer pattern's example.
* This class responsibility is to store the value and coordinate
* filters computation when they have to be applied to the value.
* Filtering responsibilities are obviously a concern of
* the Colleagues, which are Filter implementations.
*/
class InputElement
{
protected $_filters;
protected $_value;

public function addFilter(Filter $filter)
{
$this->_filters[] = $filter;
return $this;
}

public function setValue($value)
{
$this->_value = $this->_filter($value);
}

protected function _filter($value)
{
foreach ($this->_filters as $filter) {
$value = $filter->filter($value);
}
return $value;
}

public function getValue()
{
return $this->_value;
}
}

$input = new InputElement();
$input->addFilter(new NullFilter())
->addFilter(new TrimFilter())
->addFilter(new HtmlEntitiesFilter());
$input->setValue(' You should use the <h1>-<h6> tags for your headings.');
echo $input->getValue(), "\n";