© Vaskaran Sarcar 2019
Vaskaran SarcarJava Design Patternshttps://doi.org/10.1007/978-1-4842-4078-6_11

11. Composite Pattern

Vaskaran Sarcar1 
(1)
Bangalore, Karnataka, India
 

This chapter covers the composite pattern.

GoF Definition

Compose objects into tree structures to represent part-whole hierarchies. Composite lets clients treat individual objects and compositions of objects uniformly.

Concept

To help you understand this concept, I will start with an example. Consider a shop that sells different kinds of dry fruits and nuts; let’s say cashews, dates, and walnuts. Each of these items is associated with a certain price. Let’s assume that you can purchase any of these individual items or you can purchase “gift packs” (or boxed items) that contain different items. In this case, the cost of a packet is the sum of its component parts. The composite pattern is useful in a similar situation, where you treat both the individual parts and the combination of the parts in the same way so that you can process them uniformly.

This pattern is useful to represent part-whole hierarchies of objects. In object-oriented programming, a composite is an object with a composition of one-or-more similar objects, where each of these objects has similar functionalities. (This is also known as a “has-a” relationship among objects). The usage of this pattern is very common in a tree-like data structure. If you can apply it properly, you do not need to discriminate between a branch and the leaf-nodes. You can achieve two key goals with this pattern.
  • You can compose objects into a tree structure to represent a part-whole hierarchy.

  • You can access both the composite objects (branches) and the individual objects (leaf-nodes) uniformly. As a result, you can reduce the complexity of codes and at the same time, you make your application less error prone.

Real-World Example

You can also think of an organization that consists of many departments. In general, an organization has many employees. Some of these employees are grouped together to form a department, and those departments can be further grouped together to build the final structure of the organization.

Computer-World Example

Any tree data structure can follow this concept. Clients can treat the leaves of the tree and the non-leaves (or branches of the tree) in the same way.

Note

This pattern is commonly seen in various UI frameworks. In Java, the generic Abstract Window Toolkit (AWT) container object is a component that can contain other AWT components. For example, in java.awt.Container class (which extends java.awt.Component) you can see various overloaded version of add(Component comp) method. In JSF, UIViewRoot class acts like a composite node and UIOutput acts like a leaf node. When you traverse a tree, you often use the iterator design pattern, which is covered in Chapter 18.

Illustration

In this example, I am representing a college organization. Let’s assume that there is a principal and two heads of departments—one for computer science and engineering (CSE) and one for mathematics (Maths). In the Maths department, there are two teachers (or professors/lecturers), and in the CSE department, there are three teachers (or professors/lecturers). The tree structure for this organization is similar to Figure 11-1.
../images/395506_2_En_11_Chapter/395506_2_En_11_Fig1_HTML.jpg
Figure 11-1

A sample college organization

Let’s also assume that at the end, one lecturer from the CSE department retires. You’ll examine all of these cases in the following sections.

Class Diagram

Figure 11-2 shows the class diagram.
../images/395506_2_En_11_Chapter/395506_2_En_11_Fig2_HTML.jpg
Figure 11-2

Class diagram

Package Explorer View

Figure 11-3 shows the high-level structure of the program.
../images/395506_2_En_11_Chapter/395506_2_En_11_Fig3_HTML.jpg
Figure 11-3

Package Explorer view

Implementation

Here is the implementation.
package jdp2e.composite.demo;
import java.util.ArrayList;
import java.util.List;
interface IEmployee
{
    void printStructures();
    int getEmployeeCount();
}
class CompositeEmployee implements IEmployee
{
    //private static int employeeCount=0;
    private int employeeCount=0;
    private String name;
    private String dept;
    //The container for child objects
    private List<IEmployee> controls;
    //Constructor
    public CompositeEmployee(String name, String dept)
    {
        this.name = name;
        this.dept = dept;
        controls = new ArrayList<IEmployee>();
    }
    public void addEmployee(IEmployee e)
    {
        controls.add(e);
    }
    public void removeEmployee(IEmployee e)
    {
        controls.remove(e);
    }
    @Override
    public void printStructures()
    {
        System.out.println(" " + this.name + " works in  " + this.dept);
        for(IEmployee e: controls)
        {
            e.printStructures();
        }
    }
    @Override
    public int getEmployeeCount()
    {
        employeeCount=controls.size();
        for(IEmployee e: controls)
        {
            employeeCount+=e.getEmployeeCount();
        }
        return employeeCount;
    }
}
class Employee implements IEmployee
{
    private String name;
    private String dept;
    private int employeeCount=0;
    //Constructor
    public Employee(String name, String dept)
    {
        this.name = name;
        this.dept = dept;
    }
    @Override
    public void printStructures()
    {
        System.out.println(" "+this.name + " works in  " + this.dept);
    }
    @Override
    public int getEmployeeCount()
    {
        return employeeCount;//0
    }
}
class CompositePatternExample {
    /**Principal is on top of college.
     *HOD -Maths and Comp. Sc directly reports to him
     *Teachers of Computer Sc. directly reports to HOD-CSE
     *Teachers of Mathematics directly reports to HOD-Maths
     */
    public static void main(String[] args) {
        System.out.println("***Composite Pattern Demo ***");
        //2 teachers other than HOD works in Mathematics department
        Employee mathTeacher1 = new Employee("Math Teacher-1","Maths");
        Employee mathTeacher2 = new Employee("Math Teacher-2","Maths");
        //teachers other than HOD works in Computer Sc. Department
        Employee cseTeacher1 = new Employee("CSE Teacher-1", "Computer Sc.");
        Employee cseTeacher2 = new Employee("CSE Teacher-2", "Computer Sc.");
        Employee cseTeacher3 = new Employee("CSE Teacher-3", "Computer Sc.");
        //The College has 2 Head of Departments-One from Mathematics, One //from Computer Sc.
        CompositeEmployee hodMaths = new CompositeEmployee("Mrs.S.Das(HOD-Maths)","Maths");
        CompositeEmployee hodCompSc = new CompositeEmployee("Mr. V.Sarcar(HOD-CSE)", "Computer Sc.");
        //Principal of the college
        CompositeEmployee principal = new CompositeEmployee("Dr.S.Som(Principal)","Planning-Supervising-Managing");
        //Teachers of Mathematics directly reports to HOD-Maths
        hodMaths.addEmployee(mathTeacher1);
        hodMaths.addEmployee(mathTeacher2);
        //Teachers of Computer Sc. directly reports to HOD-CSE
        hodCompSc.addEmployee(cseTeacher1);
        hodCompSc.addEmployee(cseTeacher2);
        hodCompSc.addEmployee(cseTeacher3);
        /*Principal is on top of college.HOD -Maths and Comp. Sc directly reports to him*/
        principal.addEmployee(hodMaths);
        principal.addEmployee(hodCompSc);
        /*Printing the leaf-nodes and branches in the same way i.e.
         in each case, we are calling PrintStructures() method
         */
        System.out.println(" Testing the structure of a Principal object");
        //Prints the complete structure
        principal.printStructures();
        System.out.println("At present Principal has control over "+ principal.getEmployeeCount()+ " number of employees.");
        System.out.println(" Testing the structure of a HOD-CSE object:");
        //Prints the details of Computer Sc, department
        hodCompSc.printStructures();
        System.out.println("At present HOD-CSE has control over "+ hodCompSc.getEmployeeCount()+ " number of employees.");
        System.out.println(" Testing the structure of a HOD-Maths object:");
        //Prints the details of Mathematics department
        hodMaths.printStructures();
        System.out.println("At present HOD-Maths has control over "+ hodMaths.getEmployeeCount()+ " number of employees.");
        //Leaf node
        System.out.println(" Testing the structure of a leaf node:");
        mathTeacher1.printStructures();
        System.out.println("At present Math Teacher-1 has control over "+ mathTeacher1.getEmployeeCount()+ " number of employees.");
        /*Suppose, one computer teacher is leaving now
         from the organization*/
        hodCompSc.removeEmployee(cseTeacher2);
        System.out.println(" After CSE Teacher-2 resigned, the organization has following members:");
        principal.printStructures();
        System.out.println("At present Principal has control over "+ principal.getEmployeeCount()+ " number of employees");
        System.out.println("At present HOD-CSE has control over "+ hodCompSc.getEmployeeCount()+ " number of employees");
        System.out.println("At present HOD-Maths has control over "+ hodMaths.getEmployeeCount()+ " number of employees");
    }
}

Output

Here is the output. The key changes are shown in bold.
***Composite Pattern Demo ***
 Testing the structure of a Principal object
    Dr.S.Som(Principal) works in  Planning-Supervising-Managing
    Mrs.S.Das(HOD-Maths) works in  Maths
        Math Teacher-1 works in  Maths
        Math Teacher-2 works in  Maths
    Mr. V.Sarcar(HOD-CSE) works in  Computer Sc.
        CSE Teacher-1 works in  Computer Sc.
        CSE Teacher-2 works in  Computer Sc.
        CSE Teacher-3 works in  Computer Sc.
At present Principal has control over 7 number of employees.
 Testing the structure of a HOD-CSE object:
    Mr. V.Sarcar(HOD-CSE) works in  Computer Sc.
        CSE Teacher-1 works in  Computer Sc.
        CSE Teacher-2 works in  Computer Sc.
        CSE Teacher-3 works in  Computer Sc.
At present HOD-CSE has control over 3 number of employees.
 Testing the structure of a HOD-Maths object:
    Mrs.S.Das(HOD-Maths) works in  Maths
        Math Teacher-1 works in  Maths
        Math Teacher-2 works in  Maths
At present HOD-Maths has control over 2 number of employees.
 Testing the structure of a leaf node:
        Math Teacher-1 works in  Maths
At present Math Teacher-1 has control over 0 number of employees.
 After CSE Teacher-2 resigned, the organization has following members:
    Dr.S.Som(Principal) works in  Planning-Supervising-Managing
    Mrs.S.Das(HOD-Maths) works in  Maths
        Math Teacher-1 works in  Maths
        Math Teacher-2 works in  Maths
    Mr. V.Sarcar(HOD-CSE) works in  Computer Sc.
        CSE Teacher-1 works in  Computer Sc.
        CSE Teacher-3 works in  Computer Sc.
At present Principal has control over 6 number of employees
At present HOD-CSE has control over 2 number of employees
At present HOD-Maths has control over 2 number of employees

Q&A Session

  1. 1.
    What are the advantages of using composite design patterns?
    • In a tree-like structure, you can treat both the composite objects (branches) and the individual objects (leaf-nodes) uniformly. Notice that in this example, I have used two common methods: printStructures() and getEmployeeCount() to print the structure and get the employee count from both the composite object structure (principal or HODs) and the single object structure (i.e., leaf nodes like Math Teacher 1.)

    • It is very common to implement a part-whole hierarchy using this design pattern.

    • You can easily add a new component to an existing architecture or delete an existing component from your architecture.

     
  2. 2.
    What are the challenges associated with using composite design patterns?
    • If you want to maintain the ordering of child nodes (e.g., if parse trees are represented as components), you may need to use additional efforts.

    • If you are dealing with immutable objects, you cannot simply delete those.

    • You can easily add a new component but that kind of support can cause maintenance overhead in the future. Sometimes, you want to deal with a composite object that has special components. This kind of constraint can cause additional development costs because you may need to implement a dynamic checking mechanism to support the concept.

     
  3. 3.

    In this example, you have used list data structure . But I prefer to use other data structures. Is this okay?

    Absolutely. There is no universal rule. You are free to use your preferred data structure. GoF confirmed that it is not necessary to use any general-purpose data structure.

     
  4. 4.

    How can you connect the iterator design pattern to a composite design pattern?

    Go through our example once again. If you want to examine composite object architecture, you may need to iterate over the objects. In other words, if you want to do special activities with branches, you may need to iterate over its leaf nodes and non-leaf nodes. Iterator patterns are often used with composite patterns.

     
  5. 5.

    In the interface of your implementation, you defined only two methods: printStructures() and getEmployeeCount() . But you are using other methods for the addition and removal of objects in the Composite class (CompositeEmployee). Why didn’t you put these methods in the interface?

    Nice observation. GoF discussed this. Let’s look at what happens if you put the addEmployee (…) and removeEmployee (…) methods in the interface. The leaf nodes need to implement the addition and removal operations. But will it be meaningful in this case? The obvious answer is no. It may appear that you lose transparency, but I believe that you have more safety because I have blocked the meaningless operations in the leaf nodes. This is why the GoF mentioned that this kind of decision involves a trade-off between safety and transparency.

     
  6. 6.

    I want to use an abstract class instead of an interface. Is this allowed?

    In most of the cases, the simple answer is yes. But you need to understand the difference between an abstract class and an interface. In a typical scenario, you find one of them more useful than the other one. Since I am presenting only simple and easy to understand examples, you may not see much difference between the two. Particularly in this example, if I use the abstract class instead of the interface, I may put a default implementation of getEmployeeCount() in the abstract class definition. Although you can still argue that with Java’s default keyword, you could achieve the same, as in the following:
    interface IEmployee
    {
        void printStructures();
        //int getEmployeeCount();
        default public int getEmployeeCount()
        {
            return 0;
        }
    }
     

Note

In the Q&A session of the builder pattern (see Chapter 3), I discussed how to decide between an abstract class and an interface.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset