Composite Pattern

The Composite design pattern is used to treat individual objects and their compositions (groups of objects) uniformly.

It allows you to create hierarchical structures where each component (leaf or composite) can be treated as a single object.

Think of it as organizing objects into tree-like structures, where both individual objects and groups of objects can be manipulated in the same way.

Composite Pattern C++ Example:

Let’s create a simple example of the Composite pattern to represent a company’s organizational structure using employees and departments.

#include <iostream>
#include <string>
#include <vector>

// Component: Abstract class or Interface for both employees and departments
class Component {
public:
    virtual void showDetails() const = 0;
    virtual ~Component() {}
};

// Leaf: Represents an individual employee
class Employee : public Component {
public:
    Employee(const std::string& name, const std::string& role) : name_(name), role_(role) {}

    void showDetails() const override {
        std::cout << "Name: " << name_ << ", Role: " << role_ << std::endl;
    }

private:
    std::string name_;
    std::string role_;
};

// Composite: Represents a department with multiple employees (leafs)
class Department : public Component {
public:
    Department(const std::string& name) : name_(name) {}

    void showDetails() const override {
        std::cout << "Department Name: " << name_ << std::endl;
        for (const auto& employee : employees_) {
            employee->showDetails();
        }
    }

    void addEmployee(Component* employee) {
        employees_.push_back(employee);
    }

private:
    std::string name_;
    std::vector<Component*> employees_;
};

int main() {
    // Create individual employees
    Component* emp1 = new Employee("John Doe", "Software Engineer");
    Component* emp2 = new Employee("Jane Smith", "Product Manager");

    // Create departments and add employees to them
    Component* department1 = new Department("Engineering");
    department1->addEmployee(emp1);
    department1->addEmployee(emp2);

    Component* department2 = new Department("Sales");
    department2->addEmployee(new Employee("Mike Johnson", "Sales Executive"));
    department2->addEmployee(new Employee("Emily Brown", "Sales Manager"));

    // Display the details of the company's organizational structure
    department1->showDetails();
    std::cout << std::endl;
    department2->showDetails();

    // Clean up
    delete department1;
    delete department2;
    delete emp1;
    delete emp2;

    return 0;
}

Composite Pattern Explanation:

In this example, we have a Component interface, which represents both individual employees (Employee class) and departments (Department class).

The Employee class is a leaf in the composite structure, representing individual employees. It implements the Component interface and provides a method to display the details of an employee.

The Department class is a composite that represents a department with multiple employees. It also implements the Component interface and contains a vector of employees (employees_). It provides a method to add an employee to the department and displays the details of the department and its employees.

In the main() function, we demonstrate how the Composite pattern works. We create individual employees (emp1 and emp2) and departments (department1 and department2). We add employees to the departments and then display the details of the organizational structure.

Applications of the Composite Design Pattern:

  1. GUI Components: Representing the hierarchy of GUI elements like windows, buttons, and panels.
  2. File System: Representing directories and files as a tree-like structure.
  3. Organization Hierarchy: Representing hierarchical organization structures like departments and employees.

Pros of the Composite Design Pattern:

  • Uniformity: Allows treating individual objects and their compositions uniformly.
  • Flexibility: Makes it easy to add or remove components dynamically.
  • Simplified Client Code: Clients can work with complex structures without knowing the details of individual elements.

Cons of the Composite Design Pattern:

  • Complexity: May add complexity, especially when dealing with complex object hierarchies.
  • Performance: Can impact performance when handling large hierarchical structures.
  • Design Overhead: Requires careful design to ensure the correct use of leaf and composite classes.

In summary, the Composite pattern is useful when you need to treat individual objects and their compositions uniformly, especially when dealing with hierarchical structures. It provides flexibility and a simplified way to work with complex object hierarchies. However, it’s essential to consider the trade-offs and use the pattern judiciously to avoid unnecessary complexity in the codebase.

Leave a Reply