Паттерн проектирования Компоновщик (Composite) на PHP
Перед прочтением ознакомьтесь с введением в паттерны проектирования на PHP, в котором описаны принятые соглашения и понятия. Данная статья дополняется с некоторой периодичностью, так что если вы ее читали ранее, не факт что данные не изменились.
Composite (Компоновщик) относиться к классу структурных паттернов. Он используется для компоновки объектов в древовидные структуры для представления иерархий, позволяя одинаково трактовать индивидуальные и составные объекты.
Ниже на рисунке представлена типичная древовидная структура:
Как можно догадаться, composite это составной объект, а leaf это конечный потомок дерева (лист), у которого не может быть потомков. Примером такой структуры может быть XML или DOM дерево.
Основным назначением паттерна, является обеспечение единого интерфейса как к составному так и конечному объекту, что бы клиент не задумывался над тем, с каким объектом он работает. Общеизвестными примерами этого паттерна является SimpleXML и jQuery.
Структурно, компоновщик представляет собой:
Итого, мы имеем 2 класса (Leaf и Composite) наследующих единый абстрактный класс. Каждому из классов предоставляется собственноручно реализовать все абстрактные методы. Очевидно, что операции add, remove, getChild не имеют смысла для конечного объекта (листа), однако он должен их уметь обрабатывать, для совместимости со составным объектом. В некоторых случаях в них закладывается "пустая" логика, ничего не делать, на запросы не отвечать. В других же, бросать исключения и ругаться на нерасторопного программиста.
Существует еще одна реализация этого паттерна, в которой конечный объект никогда не доступен клиенту, а вместо него он получает составной объект, всего с одним элементом, конечным. В таком случае, компоновщик по совместительству является паттерном прокси. Этот случай мы не станем рассматривать, но помнить о нем стоит.
Вот пример реализации:
class ComponentException extends Exception {};
abstract class Component
{
protected $_children = array();
abstract public function Add(Component $Component);
abstract public function Remove($index);
abstract public function GetChild($index);
abstract public function GetChildren();
abstract public function Operation();
}
class Composite extends Component
{
public function Add(Component $Component)
{
$this -> _children[] = $Component;
}
public function GetChild($index)
{
if (! isset($this -> _children[$index]))
{
throw new ComponentException("Child not exists");
}
return $this -> _children[$index];
}
public function Operation()
{
print "I am composite. I have " . count($this -> GetChildren()) . " children\n";
foreach($this -> GetChildren() as $Child)
{
$Child -> Operation();
}
}
public function Remove($index)
{
if (! isset($this -> _children[$index]))
{
throw new ComponentException("Child not exists");
}
unset($this -> _children[$index]);
}
public function GetChildren()
{
return $this -> _children;
}
}
class Leaf extends Component
{
public function Add(Component $Component)
{
throw new ComponentException("I can't append child to myself");
}
public function GetChild($index)
{
throw new ComponentException("Child not exists");
}
public function Operation()
{
print "I am leaf\n";
}
public function Remove($index)
{
throw new ComponentException("Child not exists");
}
public function GetChildren()
{
return array();
}
}
Скачать его можно тут.