Composite (компоновщик) — это структурный паттерн проектирования, который позволяет сгруппировать множество объектов в древовидную структуру, а затем работать с ней так, как будто это единичный объект.
Проблема
Паттерн Компоновщик имеет смысл только тогда, когда основная модель вашей программы может быть структурирована в виде дерева.
Например, есть два объекта: Продукт и Коробка. Коробка может содержать несколько Продуктов и других Коробок поменьше. Те, в свою очередь, тоже содержат либо Продукты, либо Коробки и так далее.
Теперь предположим, ваши Продукты и Коробки могут быть частью заказов. Каждый заказ может содержать как простые Продукты без упаковки, так и составные Коробки. Ваша задача состоит в том, чтобы узнать цену всего заказа.
Если решать задачу в лоб, то вам потребуется открыть все коробки заказа, перебрать все продукты и посчитать их суммарную стоимость. Но это слишком хлопотно, так как типы коробок и их содержимое могут быть вам неизвестны. Кроме того, наперёд неизвестно и количество уровней вложенности коробок, поэтому перебрать коробки простым циклом не выйдет.
Решение
Компоновщик предлагает рассматривать Продукт и Коробку через единый интерфейс с общим методом получения стоимости.
Продукт просто вернёт свою цену. Коробка спросит цену каждого предмета внутри себя и вернёт сумму результатов. Если одним из внутренних предметов окажется коробка поменьше, она тоже будет перебирать своё содержимое, и так далее, пока не будут посчитаны все составные части.
Composite - не слишком пригодня для сохранения в БД, зато отлично подходят для сохранения в XML.
abstract class Component
{
protected $name;
public function __construct($name)
{
$this->name = $name;
}
public abstract function add(Component $c);
public abstract function remove(Component $c);
public abstract function display();
}
class Composite extends Component
{
private $children = array();
public function add(Component $component)
{
$this->children[$component->name] = $component;
}
public function remove(Component $component)
{
unset($this->children[$component->name]);
}
public function display()
{
foreach($this->children as $child){
$child->display();
}
}
}
class Leaf extends Component
{
public function add(Component $c)
{
print ("Cannot add to a leaf") ;
}
public function remove(Component $c)
{
print("Cannot remove from a leaf");
}
public function display()
{
echo $this->name . PHP_EOL;
}
}
// Create a tree structure
$root = new Composite("root");
$root->add(new Leaf("Leaf A"));
$root->add(new Leaf("Leaf B"));
$comp = new Composite("Composite X");
$comp->add(new Leaf("Leaf XA"));
$comp->add(new Leaf("Leaf XB"));
$root->add($comp);
$root->add(new Leaf("Leaf C"));
// Add and remove a leaf
$leaf = new Leaf("Leaf D");
$root->add($leaf);
$root->remove($leaf);
// Recursively display tree
$root->display();