The composite pattern is a structural design pattern which allows you to compose objects into tree structures to represent part-whole hierarchies. Composite lets clients treat individual objects and compositions of objects uniformly.
Lets take an example of creating a organizational tree hierarchies . We want to create a tree like structure where given the root employee like ceo we should be able to traverse through the hierarchy.
We will be creating the below class structures.
This pattern gives us a way to create a tree structure that can handle a nested group of employees who can be Managers and Individual contributors in the same structure. By putting Managers and Individual contributors in the same structure we create a part-whole hierarchy that is a tree of objects that is made of parts Managers and Individual contributors but that can be treated as a whole, like one big organizational hierarchy.
In this pattern we have a tree structure of Managers and Individual contributors and any employee is a composition because it can contain both other managers and IC. The individual objects are just the IC and they do not hold other objects. Using a design that follows the Composite Pattern is going to allow us to write some simple code that can apply the same operation (like traversing) over the entire employee structure.
lets code the example
Employee abstract class
public abstract class Employee { public String name; public int id; public int salary; public String designation; public Employee(String name, int id, int salary, String designation) { super(); this.name = name; this.id = id; this.salary = salary; this.designation = designation; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getId() { return id; } public void setId(int id) { this.id = id; } public int getSalary() { return salary; } public void setSalary(int salary) { this.salary = salary; } public String getDesignation() { return designation; } public void setDesignation(String designation) { this.designation = designation; } public void print() { throw new UnsupportedOperationException(); } public void addEmployee(Employee emp) { throw new UnsupportedOperationException(); } public Employee removeEmployee(Employee employee) { throw new UnsupportedOperationException(); } }
Lets code the individual contributor class which extends the employee abstract class
public class IndividualContributor extends Employee { public IndividualContributor(String name, int id, int salary, String designation) { super(name,id,salary,designation); this.name = name; this.id = id; this.salary = salary; this.designation = designation; } public void print() { System.out.println("--------------------------------"); System.out.println(this.getName()); System.out.println(this.getId()); System.out.println(this.getSalary()); System.out.println(this.getDesignation()); System.out.println("--------------------------------"); } }
Lets code the manager class which also extends from the same employee base class. The manager class also has support for additional methods like adding addEmployee and removeEmployee, but these methods does not make sense on individual contributor class so if we call these methods in individual contributor class we will throw a UnsupportedOperationException.
public class Manager extends Employee { List<Employee> listOfEmployee = new ArrayList<Employee>(); public Manager(String name, int id, int salary, String designation) { super(name,id,salary,designation); this.name = name; this.id = id; this.salary = salary; this.designation = designation; } @Override public void addEmployee(Employee employee) { listOfEmployee.add(employee); } @Override public Employee removeEmployee(Employee employee) { int index = listOfEmployee.indexOf(employee); Employee emp = listOfEmployee.get(index); return emp; } public void print() { System.out.println("###########################"); System.out.println(this.getName()); System.out.println(this.getId()); System.out.println(this.getSalary()); System.out.println(this.getDesignation()); System.out.println("###########################"); Iterator<Employee> iterator = (Iterator<Employee>) listOfEmployee.iterator(); while (iterator.hasNext()) { Employee e = (Employee) iterator.next(); e.print(); } } }
Finally we will write the client class were we will create managers and the individual contributors objects and creating the required structure.And finally we will be calling the print method on the top most object which will be called recursively if the object is of type manager or else the print method of the individual contributor will be called.
public class Test { public static void main(String[] args) { Employee suresh_ic = new IndividualContributor("suresh_ic", 1, 1000, "software enginner"); Employee samanth_ic = new IndividualContributor("samanth_ic", 2, 2000, " senior software enginner"); Employee rakesh_ic = new IndividualContributor("rakesh_ic", 3, 3000, "seniour software enginner"); Employee raghu_ic = new IndividualContributor("raghu_ic", 2, 2000, "lead enginner"); Employee veeresh_ic = new IndividualContributor("veeresh_ic", 3, 3000, "associate software enginner"); Employee stephan_ic = new IndividualContributor("stephan_ic", 4, 4000, "associate software enginner"); Employee roger_manager = new Manager("roger", 4, 4000, "lead enginner"); roger_manager.addEmployee(suresh_ic); roger_manager.addEmployee(samanth_ic); roger_manager.addEmployee(rakesh_ic); Employee rishab_manager = new Manager("rishab_manager", 1, 1000, "manager enginner"); rishab_manager.addEmployee(roger_manager); rishab_manager.addEmployee(raghu_ic); rishab_manager.addEmployee(veeresh_ic); rishab_manager.addEmployee(stephan_ic); rishab_manager.print(); } }
Below will be the output
########################### rishab_manager 1 1000 manager enginner ########################### ########################### roger 4 4000 lead enginner ########################### -------------------------------- suresh_ic 1 1000 software enginner -------------------------------- -------------------------------- samanth_ic 2 2000 senior software enginner -------------------------------- -------------------------------- rakesh_ic 3 3000 seniour software enginner -------------------------------- -------------------------------- raghu_ic 2 2000 lead enginner -------------------------------- -------------------------------- veeresh_ic 3 3000 associate software enginner -------------------------------- -------------------------------- stephan_ic 4 4000 associate software enginner --------------------------------