Composite Pattern
The Composite Pattern, also known as the Part-Whole Pattern, is used to treat a group of objects in a similar way as a single object. The Composite Pattern composes objects in a tree structure to represent part-whole hierarchies. This type of design pattern is a structural pattern that creates a tree structure of groups of objects.
This pattern creates a class that contains a group of its own objects. The class provides ways to modify the same group of objects.
We demonstrate the usage of the Composite Pattern through an example that shows the hierarchical structure of employees in an organization.
Introduction
Intent: Compose objects into tree structures to represent part-whole hierarchies. The Composite Pattern allows clients to treat individual objects and compositions of objects uniformly.
Main Solution: It blurs the concept of simple and complex elements in our tree-like structures. Client programs can handle complex elements as if they were simple elements, decoupling the client program from the internal structure of complex elements.
When to Use: 1. You want to represent part-whole hierarchies of objects (tree structures).
- You want users to ignore the differences between compositions of objects and individual objects, allowing users to work with all objects in the composite structure uniformly.
How to Solve: Branches and leaves implement a unified interface, with branches internally composing this interface.
Key Code: Branches internally compose this interface and contain an internal List property to hold Components.
Example Applications: 1. Arithmetic expressions include operands, operators, and another operand, where the other operand can also be an operand, operator, and another operand.
- In JAVA AWT and SWING, Button and Checkbox are leaves, and Container is a branch.
Advantages: 1. High-level modules are easy to call.
- Nodes can be freely added.
Disadvantages: When using the Composite Pattern, the declarations of leaves and branches are implementation classes rather than interfaces, violating the Dependency Inversion Principle.
Usage Scenarios: Part-whole scenarios, such as tree-like menus, file and folder management.
Notes: Define concrete classes.
Implementation
We have a class Employee that serves as the composite model class. The CompositePatternDemo class uses the Employee class to add department hierarchies and print all employees.
Step 1
Create the Employee class, which contains a list of Employee objects.
Employee.java
import java.util.ArrayList;
import java.util.List;
public class Employee {
private String name;
private String dept;
private int salary;
private List<Employee> subordinates;
// Constructor
public Employee(String name, String dept, int sal) {
this.name = name;
this.dept = dept;
this.salary = sal;
subordinates = new ArrayList<Employee>();
}
public void add(Employee e) {
subordinates.add(e);
}
public void remove(Employee e) {
subordinates.remove(e);
}
public List<Employee> getSubordinates(){
return subordinates;
}
public String toString(){
return ("Employee :[ Name : "+ name
+", dept : "+ dept + ", salary :"
+ salary+" ]");
}
}
Step 2
Use the Employee class to create and print the hierarchy of employees.
CompositePatternDemo.java
public class CompositePatternDemo {
public static void main(String[] args) {
Employee CEO = new Employee("John","CEO", 30000);
Employee headSales = new Employee("Robert","Head Sales", 20000);
Employee headMarketing = new Employee("Michel","Head Marketing", 20000);
Employee clerk1 = new Employee("Laura","Marketing", 10000);
Employee clerk2 = new Employee("Bob","Marketing", 10000);
Employee salesExecutive1 = new Employee("Richard","Sales", 10000);
Employee salesExecutive2 = new Employee("Rob","Sales", 10000);
CEO.add(headSales);
CEO.add(headMarketing);
headSales.add(salesExecutive1);
headSales.add(salesExecutive2);
headMarketing.add(clerk1);
headMarketing.add(clerk2);
// Print all employees of the organization
System.out.println(CEO);
for (Employee headEmployee : CEO.getSubordinates()) {
System.out.println(headEmployee);
for (Employee employee : headEmployee.getSubordinates()) {
System.out.println(employee);
}
}
}
}
Step 3
Execute the program, and the output will be:
Employee :[ Name : John, dept : CEO, salary :30000 ]
Employee :[ Name : Robert, dept : Head Sales, salary :20000 ]
Employee :[ Name : Richard, dept : Sales, salary :10000 ]
Employee :[ Name : Rob, dept : Sales, salary :10000 ]
Employee :[ Name : Michel, dept : Head Marketing, salary :20000 ]
Employee :[ Name : Laura, dept : Marketing, salary :10000 ]
Employee :[ Name : Bob, dept : Marketing, salary :10000 ]