Wednesday, September 19, 2012

Composite design pattern in java

Composite design patten allows you to have a tree structure and ask each node in the tree structure to perform a task.You can take real life example of a organization.It have general managers and under general managers, there can be managers and  under managers there can be developers.Now you can set a tree structure and ask each node to perform common operation like getSalary().

As described by Gof:
"Compose objects into tree structure to represent part-whole hierarchies.Composite lets client treat individual objects and compositions of objects uniformly".

Composite design pattern treats each node in two ways-Composite or leaf.Composite means it can have other objects below it.leaf means it has no objects below it.

Tree structure:


When to use it:

  • you want to represent part-whole hierachies of objects.
  • you want client to be able to ignore difference between compositions of objects and individual objects.Clients will treat all objects in the composite structure uniformly.

UML Diagram for Composite design pattern:

    Elements:

    • Component
      • declares interface for objects in composition.
      • implements deafault behaviour for the interface common to all classes as appropriate.
      • declares an interface for accessing and managing its child components.
    • Leaf
      • represents leaf objects in the composition.A leaf has no children.
      • defines behaviour for primitive objects in the composition.
    • Composite
      • defines behaviour for components having children.
      • stores child components.
      • implements child related operations in the component interface.
    • Client
      • manipulates objects in the composition through the component interface.

    WorkFlow:

    Client use the component class interface to interact with objects in the composition structure.if recipient is a leaf then request is handled directly.If recipient is a composite,then it usually forwards request to its child components,possibly performing additional operations before and after forwarding.

    Recursion:

    What makes the Composite pattern one of the most beautiful is the power of recursion. I can explain this with the same organization example. You want to find the total salary paid to all employees of the organization. It is nothing but the salary of CEO + the salary paid to all the departments. What is the salary of a department? It is the salary of the department head + the salary of all projects. What is the total salary of a project? It is the salary of the project manager + the salary of all the project members. In short, the salary of anything is the salary of self + the salary of all its sub groups.

    Example:

    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.

    Tree structure for example:

    UML diagram for above example:


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

    Java code for all above classes:

    First we will create component inrteface.It represents object in composition .It has all common operation that will be applicable to both manager and developer.
    Employee.java(Component) :

    package org.arpit.javapostsforlearning.designpatterns;

    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();
    }
    Now we will create manager(composite class).Key point here is that all common method delegates its operations to child objects.It has method to access and modify its children.
    Manager.java(Composite):

    package org.arpit.javapostsforlearning.designpatterns;

    import java.util.ArrayList;
    import java.util.Iterator;
    import java.util.List;

    public class Manager implements Employee{

    private String name;
    private double salary;

    public Manager(String name,double salary){
    this.name = name;
    this.salary = salary;
    }

    List<Employee> employees = new ArrayList<Employee>();
    public void add(Employee employee) {
    employees.add(employee);
    }

    public Employee getChild(int i) {
    return employees.get(i);
    }

    public String getName() {
    return name;
    }

    public double getSalary() {
    return salary;
    }

    public void print() {
    System.out.println("-------------");
    System.out.println("Name ="+getName());
    System.out.println("Salary ="+getSalary());
    System.out.println("-------------");

    Iterator<Employee> employeeIterator = employees.iterator();
    while(employeeIterator.hasNext()){
    Employee employee = employeeIterator.next();
    employee.print();
    }
    }

    public void remove(Employee employee) {
    employees.remove(employee);
    }

    }

    We will create developer class.This class is leaf node so all operations related to accessing children will be empty as it has no children.
    Developer.java(Leaf):
    package org.arpit.javapostsforlearning.designpatterns;
    /**
     * In this class,there are many methods which are not applicable to developer because
     * it is a leaf node.
     */

    public class Developer implements Employee{

        private String name;
        private double salary;

        public Developer(String name,double salary){
            this.name = name;
            this.salary = salary;
        }
        public void add(Employee employee) {
            //this is leaf node so this method is not applicable to this class.
        }

        public Employee getChild(int i) {
            //this is leaf node so this method is not applicable to this class.
            return null;
        }

        public String getName() {
            return name;
        }

        public double getSalary() {
            return salary;
        }

        public void print() {
            System.out.println("-------------");
            System.out.println("Name ="+getName());
            System.out.println("Salary ="+getSalary());
            System.out.println("-------------");
        }

        public void remove(Employee employee) {
            //this is leaf node so this method is not applicable to this class.
        }

    }

    CompositeDesignPatternMain.java:
    package org.arpit.javapostsforlearning.designpatterns;

    public class CompositeDesignPatternMain {

    public static void main(String[] args) {
    Employee emp1=new Developer("John", 10000);
    Employee emp2=new Developer("David", 15000);
    Employee manager1=new Manager("Daniel",25000);
    manager1.add(emp1);
    manager1.add(emp2);
    Employee emp3=new Developer("Michael", 20000);
    Manager generalManager=new Manager("Mark", 50000);
    generalManager.add(emp3);
    generalManager.add(manager1);
    generalManager.print();
    }
    }

    Output:
    -------------
    Name =Mark
    Salary =50000.0
    -------------
    -------------
    Name =Michael
    Salary =20000.0
    -------------
    -------------
    Name =Daniel
    Salary =25000.0
    -------------
    -------------
    Name =John
    Salary =10000.0
    -------------
    -------------
    Name =David
    Salary =15000.0
    -------------

    Disadvantages:

    • Once tree structure is defined,comosite design makes tree overly general.
    • Leaf class have to create some methods which has to empty.

    Usage in JDK:

    • java.util.Map#putAll(Map)
    • java.util.List#addAll(Collection)
    • java.util.Set#addAll(Collection)
    • java.nio.ByteBuffer#put(ByteBuffer) (also on CharBuffer, ShortBuffer, IntBuffer, LongBuffer, FloatBuffer and DoubleBuffer)
    • java.awt.Container#add(Component) 

    No comments:

    Post a Comment