Design patterns: Composite
The Composite Pattern lets you treat individual objects and compositions of objects uniformly. This pattern is useful when you have a hierarchical structure where individual objects and groups of objects need to be treated the same way.
Characteristics of the Composite pattern
- Tree structure: The Composite Pattern lets you build a tree structure made up of individual objects (leaves) and composite objects (nodes). This structure makes it easy to represent objects hierarchically.
- Uniform treatment: It lets you treat individual objects and groups of objects uniformly. Clients can interact with both using the same interface, simplifying the client code.
- Flexibility: It lets you add new components, both at the individual-object level and at the group level, without modifying existing code. This promotes maintainability and extensibility.
- Simpler object management: It reduces the complexity of managing objects, letting clients work with a simple interface to build and manipulate complex structures.
- Recursion: The Composite Pattern is often recursive, letting you build nested object structures. The methods defined in the interface can be called recursively on every level of the structure.
Example in PHP:
Imagine you want to represent a hierarchical structure of folders and files in a file system. Folders can contain other files or folders. The Composite Pattern lets you treat both files and folders as “composite” objects.
// Common component interface
interface FileSystemComponent {
public function showDetails();
}
// Leaf object: the file
class File implements FileSystemComponent {
private $name;
public function __construct($name) {
$this->name = $name;
}
public function showDetails() {
echo "File: $this->name\n";
}
}
// Composite object: the folder
class Folder implements FileSystemComponent {
private $name;
private $components = [];
public function __construct($name) {
$this->name = $name;
}
public function addComponent(FileSystemComponent $component) {
$this->components[] = $component;
}
public function showDetails() {
echo "Folder: $this->name\n";
foreach ($this->components as $component) {
$component->showDetails(); // We treat files and folders the same way
}
}
}
// Usage
$file1 = new File("file1.txt");
$file2 = new File("file2.txt");
$file3 = new File("file3.txt");
$folder1 = new Folder("folder1");
$folder2 = new Folder("folder2");
$folder1->addComponent($file1);
$folder1->addComponent($file2);
$folder2->addComponent($file3);
$folder2->addComponent($folder1);
$folder2->showDetails();
/*
Output:
Folder: folder2
File: file3.txt
Folder: folder1
File: file1.txt
File: file2.txt
*/