Composite is a structural design pattern that lets you compose objects into tree structures and then work with these structures as if they were individual objects.
Using the Composite pattern makes sense only when the core model of your app can be represented as a tree.
For example, imagine that you have two types of objects: Products and Boxes. A Box can contain several Products as well as a number of smaller Boxes. These little Boxes can also hold some Products or even smaller Boxes, and so on.
Use the Composite pattern when you have to implement a tree-like object structure.
The Composite pattern provides you with two basic element types that share a common interface: simple leaves and complex containers
A container can be composed of both leaves and other containers. This lets you construct a nested recursive object structure that resembles a tree.
You can work with complex tree structures more conveniently: use polymorphism and recursion to your advantage.
Open/Closed Principle. You can introduce new element types into the app without breaking the existing code, which now works with the object tree.
RenderableInterface.php
<?php
namespace DesignPatterns\Structural\Composite;
interface RenderableInterface
{
public function render(): string;
}
<?php
namespace DesignPatterns\Structural\Composite;
/**
* The composite node MUST extend the component contract. This is mandatory for building
* a tree of components.
*/
class Form implements RenderableInterface
{
/**
* @var RenderableInterface[]
*/
private $elements;
/**
* runs through all elements and calls render() on them, then returns the complete representation
* of the form.
*
* from the outside, one will not see this and the form will act like a single object instance
*
* @return string
*/
public function render(): string
{
$formCode = '<form>';
foreach ($this->elements as $element) {
$formCode .= $element->render();
}
$formCode .= '</form>';
return $formCode;
}
/**
* @param RenderableInterface $element
*/
public function addElement(RenderableInterface $element)
{
$this->elements[] = $element;
}
}
<?php
namespace DesignPatterns\Structural\Composite;
class InputElement implements RenderableInterface
{
public function render(): string
{
return '<input type="text" />';
}
}
<?php
namespace DesignPatterns\Structural\Composite;
class TextElement implements RenderableInterface
{
/**
* @var string
*/
private $text;
public function __construct(string $text)
{
$this->text = $text;
}
public function render(): string
{
return $this->text;
}
}
Composite and Decorator have similar structure diagrams since both rely on recursive composition to organize an open-ended number of objects.
A Decorator is like a Composite but only has one child component. There’s another significant difference: Decorator adds additional responsibilities to the wrapped object, while Composite just “sums up” its children’s results.