Composite Design Pattern in Kotlin

1. Definition

The Composite Design Pattern allows you to compose objects into tree structures to represent part-whole hierarchies. With this pattern, clients treat individual objects and compositions of objects uniformly.

2. Problem Statement

Imagine an organization with employees. Some employees are managers who have other employees reporting to them. We need a way to manage this hierarchy efficiently, where an individual employee and a manager (with their team) can be treated uniformly.

3. Solution

Use the Composite pattern to define both individual objects (Employee) and compositions (Manager) in such a way that they can be manipulated in the same manner regardless of their complexity.

4. Real-World Use Cases

1. Graphics where shapes can be composed of other shapes (e.g., a drawing containing lines, circles, and groups of shapes).

2. File system directories where a directory can contain files or other directories.

5. Implementation Steps

1. Define a component interface that makes individual and composite objects uniform.

2. Create leaf objects that implement the component.

3. Create composite objects that also implement the component and have children.

6. Implementation in Kotlin Programming

// Component
interface Employee {
    fun showDetails(): String
}
// Leaf
class Developer(private val name: String, private val position: String) : Employee {
    override fun showDetails() = "Developer: $name, Position: $position"
}
// Composite
class Manager(private val name: String, private val position: String) : Employee {
    private val employees: MutableList<Employee> = mutableListOf()
    fun addEmployee(employee: Employee) {
        employees.add(employee)
    }
    fun removeEmployee(employee: Employee) {
        employees.remove(employee)
    }
    override fun showDetails(): String {
        val employeeDetails = employees.joinToString("\n") { it.showDetails() }
        return "Manager: $name, Position: $position\n$employeeDetails"
    }
}
fun main() {
    val dev1 = Developer("John Doe", "Frontend Developer")
    val dev2 = Developer("Jane Smith", "Backend Developer")
    val manager = Manager("Ella White", "Tech Lead")
    manager.addEmployee(dev1)
    manager.addEmployee(dev2)
    println(manager.showDetails())
}

Output:

Manager: Ella White, Position: Tech Lead
Developer: John Doe, Position: Frontend Developer
Developer: Jane Smith, Position: Backend Developer

Explanation:

1. Employee is the component interface that provides a uniform method showDetails.

2. Developer is a leaf that implements the Employee interface.

3. Manager is a composite that contains a list of Employees and implements the same interface. It can add or remove employees.

4. In the main function, we created a manager with two developers reporting to her and displaying their details uniformly.

7. When to use?

The Composite pattern should be used when:

1. You want to represent part-whole hierarchies of objects.

2. You want clients to treat individual objects and compositions uniformly.

3. The structure can have any level of complexity, and you want a unified way to manage it.

Comments