Introduction
Composite pattern is used where we need to treat a group of objects in similar way as a single object. Composite pattern composes objects in term of a tree structure to represent part as well as whole hierarchy. This pattern creates a class that contains group of its own objects. This class provides ways to modify its group of same objects. Consider for example a program that manipulates a file system. A file system is a tree structure that contains branches which are folders as well as leaf nodes which are files. Folder object usually contains one or more file or folder objects and thus is a complex object where a file is a simple object. Since files and folders have many operations and attributes in common, such as moving and copying a file or a folder, listing file or folder attributes such as file name and size, it would be easier and more convenient to treat both file and folder objects uniformly by defining a File System Resource Interface.
Intent
- Compose objects into tree structures to represent whole-part hierarchies. Composite lets clients treat individual objects and compositions of objects uniformly.
- Recursive composition
Implementation
It has four participants:
- Component is the abstraction for leafs and composites. It defines the interface that must be implemented by the objects in the composition.
- Leafs are objects that have no children. They implement services described by the Component interface.
- Composite stores child components in addition to implementing methods defined by the Component interface. Composites implement methods defined in the Component interface by delegating to child components.
- Client manipulates the objects in the composition through the component interface.
Example
// Composite Design Pattern example of a company with different employee details // A common interface for all employee interface Employee { public void showEmployeeDetails(); } class Developer implements Employee { private String name; private long empId; public Developer(long empId, String name) { this.empId = empId; this.name = name; } @Override public void showEmployeeDetails() { System.out.println(empId+" " +name); } } class Manager implements Employee { private String name; private long empId; public Manager(long empId, String name) { this.empId = empId; this.name = name; } @Override public void showEmployeeDetails() { System.out.println(empId+" " +name); } } // Class used to get Employee List and do the opertions like add or remove Employee class CompanyDirectory implements Employee { private List<Employee> employeeList = new ArrayList<Employee>(); @Override public void showEmployeeDetails() { for(Employee emp:employeeList) { emp.showEmployeeDetails(); } } public void addEmployee(Employee emp) { employeeList.add(emp); } public void removeEmployee(Employee emp) { employeeList.remove(emp); } } // Driver class public class Company { public static void main (String[] args) { Developer d1 = new Developer(100, "Lokesh Sharma"); Developer d2 = new Developer(101, "Vinay Sharma"); CompanyDirectory engDirectory = new CompanyDirectory(); engDirectory.addEmployee(d1); engDirectory.addEmployee(d2); Manager m1 = new Manager(200, "Kushagra Garg"); Manager m2 = new Manager(201, "Vikram Sharma "); CompanyDirectory accDirectory = new CompanyDirectory(); accDirectory.addEmployee(m1); accDirectory.addEmployee(m2); CompanyDirectory directory = new CompanyDirectory(); directory.addEmployee(engDirectory); directory.addEmployee(accDirectory); directory.showEmployeeDetails(); } }