Friday, February 28, 2014

Structural Design Pattern : Composite Design Pattern



The GoF says you use the Composite design pattern to “Compose objects into tree structures to represent part-whole hierarchies. Composite lets clients treat individual objects and compositions of objects uniformly.

Motivation

When dealing with Tree-structured data, programmers often have to discriminate between a leaf-node and a branch. This makes code more complex, and therefore, error prone. The solution is an interface that allows treating complex and primitive objects uniformly.

The composite pattern describes that a group of objects are to be treated in the same way as a single instance of an object. The intent of a composite is to "compose" objects into tree structures to represent part-whole hierarchies

 
What is Part-whole hierarchy?
A system consists of subsystems or components. Components can further be divided into smaller components. Further smaller components can be divided into smaller elements. This is a part-whole hierarchy.

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 type of design pattern comes under structural pattern as this pattern creates a tree structure of group of objects.

To implement the Composite pattern, the GoF suggests that you use an abstract class as the basis for both the leaves and branches in the tree. Doing so gives the leaves and branches a common set of methods, which is what the Composite pattern is all about.


Example 1


In a small organization,there are 5 employees.At top position,there is 1 general manager. Under general manager,there are two employees, one is manager and other is developer and further manager has two developers working under him. We want to print name and salary of all employees from top to bottom.
  



Comparing from above generic elements. Our example consist of following elements.
  • Manager(Composite)
  • Developer(Leaf)
  • Employee(Component) 


Employee.java(Component)

 

 public interface Employee {  
   public void add(Employee employee);  
   public void remove(Employee employee);  
   public Employee getChild(int i);  
   public String getName();  
   public double getSalary();  
   public void print();  
 }  




Manager.java(Composite)


 public class Manager implements Employee {  
      private String name;      private double salary;  
      List<Employee> employees = new ArrayList<Employee>();  
      public Manager(String n, double d) {  
           name = n;      salary = d;  
      }  
      @Override  
      public void add(Employee employee) {  
           employees.add(employee);  
      }  
      @Override  
      public Employee getChild(int i) {  
           return employees.get(i);  
      }  
      @Override  
      public String getName() {      return name; }  
      @Override  
      public double getSalary() { return salary; }  
      @Override  
      public void print() {  
           System.out.println("Manager Name =" + getName());  
           System.out.println("Manager Salary =" + getSalary());  
           Iterator<Employee> employeeIterator = employees.iterator();  
           while (employeeIterator.hasNext()) {  
                Employee employee = employeeIterator.next();  
                employee.print();  
           }  
      }  
      @Override  
      public void remove(Employee employee) {  
           employees.remove(employee);  
      }}  

 Developer.java(Leaf)


/**
 * In this class,there are many methods which are not applicable to developer because  * it is a leaf node.  */
 

1:  public class Developer implements Employee {  
2:    private String name;   private double salary;  
3:          public Developer(String name,double salary) {  
4:              this.name = name;  
5:              this.salary = salary;   
6:            }  
7:       @Override  
8:       public void add(Employee employee) {  
9:             //this is leaf node so this method is not applicable to this class.  
10:       }  
11:       @Override  
12:       public Employee getChild(int i) {  
13:            return null;  
14:       }  
15:       @Override  
16:       public String getName() {  
17:            return name;  
18:       }  
19:       @Override  
20:       public double getSalary() {  
21:                 return salary;  
22:       }  
23:       @Override  
24:       public void print() {  
25:         System.out.println("-------------");  
26:      System.out.println("Dev Name ="+getName()+"Dev Salary ="+getSalary());  
27:      System.out.println("-------------");  
28:       }  
29:       @Override  
30:       public void remove(Employee employee) {  
31:            //this is leaf node so this method is not applicable to this class.   
32:       }  
33:  }  


 


1:  public class CompositeDesignPatternMain {  
2:       public static void main(String[] args) {  
3:             Employee empManager = new Manager("Sam",25000);  
4:             Employee emp1   = new Developer("Gubbo", 10000);  
5:             Employee emp2   = new Developer("TG", 15000);  
6:             empManager.add(emp1);   
7:             empManager.add(emp2);  
8:             Employee emp3=new Developer("AP", 20000);  
9:             //Manager generalManager=new Manager("JA", 50000); NOT This   
10:             Employee empGM = new Manager("JA", 50000);  
11:             empGM.add(emp3);  
12:             empGM.add(empManager);  
13:             empGM.print();  
14:       } }  



Output of the program

Manager Name =JA
Manager Salary =50000.0
-------------
Dev Name =AP
Dev Salary =20000.0
-------------
Manager Name =Sam
Manager Salary =25000.0
-------------
Dev Name =Gubbo
Dev Salary =10000.0
-------------
-------------
Dev Name =TG
Dev Salary =15000.0
-------------

 
As seen in the output, the composite pattern allows us to perform operations on the composites and leaves that make up a tree structure via a common interface.




Example 2 : 


1:  public interface Group {  
2:   public void assemble();  
3:   public void addGroup(Group g);  
4:   public void removeGroup(Group g);  
5:  }  



1:  public class Block implements Group {  
2:       @Override  
3:       public void assemble() {  
4:            System.out.println(" Assemble the Block ");  
5:       }  
6:       @Override  
7:       public void addGroup(Group g) {  
8:            // No need to implement Group functionality as LEAF NODE   
9:       }  
10:       @Override  
11:       public void removeGroup(Group g) {  
12:            // No need to implement Group functionality as LEAF NODE   
13:       }  
14:  }  


1:  public class Structure implements Group {  
2:       private List<Group> groups = new ArrayList<Group>();  
3:       public void addGroup(Group group){  
4:            groups.add(group);  
5:       }  
6:       public void removeGroup(Group group){  
7:            groups.remove(group);  
8:       }  
9:       @Override  
10:       public void assemble() {  
11:            for(Group gp : groups){  
12:                 gp.assemble();  
13:            }  
14:       }  
15:  }  


1:  public class CompositeTest {  
2:       public static void main(String[] args) {  
3:            Block b1 = new Block();  
4:            Block b2 = new Block();  
5:            Block b3 = new Block();  
6:            Structure structure1 = new Structure();  
7:            Structure structure3 = new Structure();  
8:            Structure structure2 = new Structure();  
9:            structure1.addGroup(b1);  
10:            structure1.addGroup(b2);  
11:            structure2.addGroup(b3);  
12:            structure3.addGroup(structure1);  
13:            structure3.addGroup(structure2);  
14:            structure3.assemble();  
15:       }  
16:  }  


Output of the program

Assemble the Block
Assemble the Block
Assemble the Block


Notes :
  • Importance of composite pattern is, the group of objects should be treated similarly as a single object.
  • Manipulating a single object should be as similar to manipulating a group of objects. In sync with our example, we join primitive blocks to create structures and similarly join structures to create house.
  • Recursive formation and tree structure for composite should be noted.
  • Clients access the whole hierarchy through the components and they are not aware about if they are dealing with leaf or composites.


Advantages of Composite pattern:
  • Compose more than one similar objects so that they can be manipulated as one object.
  • Flexibility of structure and manageable interface.
  • Structure can be changed anytime by calling the respective methods (add or remove) on a composite.
 
Java Usage / Java Real time
  • java.awt.Container#add(Component) – in awt, we have containers and components – a classic implementation
  • javax.faces.component.UIComponent#getChildren()
  • File System Implementation
  • The Apache Struts framework includes a JSP tag library, known as Tiles, that lets you compose a Webpage from multiple JSPs. Tiles is actually an implementation of the J2EE (Java 2 Platform, Enterprise Edition) CompositeView pattern, itself based on the Design Patterns Composite pattern.  
  •  


Related Patterns
Decorator Pattern - Decorator is often used with Composite. When decorators and composites are used together, they will usually have a common parent class. So decorators will have to support the Component interface with operations like Add, Remove, and GetChild.



No comments: