Composite Design Pattern
A composite design pattern is a structural design pattern that allows you to compose objects into tree structures and then work with these structures as if they were individual objects. It is useful when you want to represent part-whole hierarchies of objects and treat them uniformly.
For example, suppose you have a product catalog that consists of products and product categories. A product has a name and a price, while a product category has a name and a list of products or subcategories. You want to be able to calculate the total price of a product category by adding up the prices of all the products and subcategories it contains.
One way to implement this is to use a composite design pattern. You can define an abstract interface called ProductComponentInterface that declares the common methods for both products and product categories, such as getPrice() and getName(). Then, you can implement this interface in two concrete classes: Product and ProductCategory. The Product class simply returns its own name and price, while the ProductCategory class maintains an array of ProductComponentInterface objects and implements the methods by iterating over them.
The advantage of this approach is that you can treat both products and product categories as ProductComponentInterface objects and manipulate them with the same code. For example, you can add products or subcategories to a product category, or nest product categories inside other product categories, without changing the logic of the getPrice() method. You can also use polymorphism to handle different types of ProductComponentInterface objects without checking their types explicitly.
Here is a code example that demonstrates how to use the composite design pattern in PHP:
<?php
// Create some products
$product1 = new Product('Test Product', 100);
$product2 = new Product('Test Product 2', 200);
$product3 = new Product('Test Product 3', 300);// Create a product category and add two products to it
$products = new ProductCategory('Test Category');
$products->add($product1);
$products->add($product2);// Create another product category and add one product and the previous category to it
$products2 = new ProductCategory('Test Category 2');
$products2->add($product3);
$products2->add($products);// Get the total price of the second category
echo $products2->getPrice(); // Prints 600// The following classes and interfaces are defined in separate files
<?php
// The ProductCategory class implements the composite part of the pattern
class ProductCategory implements ProductComponentInterface
{ // An array of ProductComponentInterface objects
private array $products = []; // The constructor takes the name of the category as an argument
public function __construct(private readonly string $name)
{
} // The add method allows adding products or subcategories to the category
public function add(ProductComponentInterface $product): void
{
$this->products[] = $product;
} // The getPrice method returns the sum of the prices of all the products and subcategories in the category
public function getPrice(): float
{
$total = 0;
foreach ($this->products as $product) {
$total += $product->getPrice();
}
return $total;
} // The getName method returns the name of the category
public function getName(): string
{
return $this->name;
}
}
interface ProductComponentInterface
{
// The common interface for both products and product categories
public function getPrice(): float;
public function getName(): string;
}
// The Product class implements the leaf part of the pattern
readonly class Product implements ProductComponentInterface
{ // The constructor takes the name and price of the product as arguments
public function __construct(private string $name, private float $price)
{
} // The getName method returns the name of the product
public function getName(): string
{
return $this->name;
} // The getPrice method returns the price of the product
public function getPrice(): float
{
return $this->price;
}
}
I’m not sure why anyone would need this pattern for a backend system, but I guess it’s kind of cool. Here’s a GitHub repo that shows how to do it and a YouTube video that explains it better. Check them out if you’re interested.
https://github.com/Adams-Ijachi/design-patterns
https://www.youtube.com/watch?v=EWDmWbJ4wRA&list=PLrhzvIcii6GNjpARdnO4ueTUAVR9eMBpc&index=14