Tuesday, May 2, 2023

How to use Composite Design Pattern in Java? Example Tutorial

Hello Java Programmers, if you want to learn about Composite Design patterns in Java, like how to implement Composite design pattern and when to use it then you have come to the right place. Earlier, I have shared the best Java design pattern courses and in this article, I am going to talk about Composite design Patterns, one of the 24 GOF patterns described in the classic Object Oriented design pattern book.  Composite Design Pattern is a behavioral design pattern from GOF, first described in their classic book design pattern. The composite pattern allows you to build a structure as a tree, which contains both leaf and composites

A leaf is an Object, corresponding to a leaf node in Tree, which doesn't contain another object, while the Composite object contains other composites or leaves. One of the most powerful features of this design pattern is that you can deal with both leaf and composite in the same way. 

For example, you have an organization chart that contains every employee in hierarchical order.  Some Employees are Managers and they contain the reference to other employees who report to them.  If you need to print all direct for a list of employees, you can not do this without checking if a particular Employee is a Manager or not.

One way to remove this check is by using the Composite pattern, which allows treating both normal employees and managers in the same way, and that's what you will see in this tutorial. We will use exactly this example to implement the Composite Design Pattern in Java. 

Btw, if you want to master Object-Oriented Design Pattern in Java then I highly recommend Design Patterns in Java course by Dmitri Nestruk on Udemy. This is one of the best design pattern courses to learn the modern implementation of classic design patterns in Java. You will not only learn how to recognize and apply design patterns but also how to Refactor existing designs to use patterns for better code quality. 





What is Composite Design Pattern? An Example

Here is an example of the Composite pattern in Java. Here we have used the Composite pattern to represent employees in an organization. Here some employees are Managers, who are the composite objects because they contain the reference to other employees who report to them. 

If we need to print directs(employees who report to him) for a list of employees, we can not do this without checking if this employee is a Manager or not. One way to remove this check is by using the Composite pattern, which allows treating both normal employees and managers in the same way.

In composite design pattern, we have a Component object, which defines a method for both leaf and composite objects, in this example it is Employee, who has methods like add(Employee e), remove(Employee e) as well as normal methods like getId(), getName().

In our example, Employee is an abstract class, to provide a default implementation for most of the methods and it has two concrete subclasses Developer and Manager.

Manager overrides directs() method to return a list of Employees, who reports to him, while developer just returns an empty list, which is also a good example of avoiding NullPointerException using null object pattern.  

If you want to learn more about Design Patterns and what problems they solve, I highly recommend you to join Software Design Patterns: Best Practices for Software Developers course on Educative, an interactive learning platform that allows you to run code in the browser. You can practice design patterns right in your browser. 

Composite Design Pattern in Java  [ Real world Example]

And, if you find the Educative platform and their Grokking courses like Grokking the System Design Interview, Grokking the Object-Oriented Programming interview then consider getting an Educative Subscription which provides access to their 250+ courses for just $14.9 per month. It's very cost-effective and great for preparing for coding interviews. 


And, here is the complete code for this example

Employee.java

import java.util.List;

public abstract class Employee {
  protected int id;
  protected String name;

  public Employee(int id, String name) {
    this.id = id;
    this.name = name;
  }

  public int getId() {
    return id;
  }

  public String getName() {
    return name;
  }

  public void add(Employee e) {
    throw new UnsupportedOperationException();
  }

  public void remove(Employee e) {
    throw new UnsupportedOperationException();
  }

  public Employee getChild(int i) {
    throw new UnsupportedOperationException();
  }

  public List<Employee> directs() {
    throw new UnsupportedOperationException();
  }

  @Override
  public String toString() {
    return String.format("%s: %d", name, id);
  }
}

Developer.java (Leaf object)

import java.util.Collections;
import java.util.List;

public class Developer extends Employee {
  public Developer(int id, String name) {
    super(id, name);
  }

  @Override
  public List<Employee> directs() {
    return Collections.EMPTY_LIST;
  }
}

Manager.java

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

public class Manager extends Employee {
  private List<Employee> directs = new ArrayList<>();

  public Manager(int id, String name) {
    super(id, name);
  }

  @Override
  public void add(Employee e) {
    directs.add(e);
  }

  @Override
  public void remove(Employee e) {
    directs.add(e);
  }

  @Override
  public Employee getChild(int i) {
    return directs.get(i);
  }

  @Override
  public List<Employee> directs() {
    return directs;
  }
}


CompositePattern.java

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

/**
 * Java Program to demonstrate how Composite design pattern works internally.
 * 
 * @author Javarevisited
 *
 */
public class CompositePatternTest {

  public static void main(String args[]) {

    // creating a bunch of developers
    Developer john = new Developer(101, "John");
    Developer robin = new Developer(102, "Robin");
    Developer peter = new Developer(103, "Peter");
    Developer luke = new Developer(104, "Luke");
    Developer amy = new Developer(105, "Amy");

    // creating a manager and adding developers under him
    Manager steve = new Manager(106, "Steve");
    steve.add(john);
    steve.add(robin);
    steve.add(peter);

    // creating another manager and adding his directs
    Manager frank = new Manager(107, "Frank");
    frank.add(luke);
    frank.add(amy);
    frank.add(steve);

    // creating a list of Employee
    List<Employee> org = new ArrayList<>();
    org.add(john);
    org.add(robin);
    org.add(peter);
    org.add(luke);
    org.add(amy);
    org.add(steve);
    org.add(frank);

    // iterating over all employees
    for (Employee e : org) {
      System.out.printf("%s manages %s %n", e.getName(), e.directs());
    }
  }
}

Output
John manages []
Robin manages []
Peter manages []
Luke manages []
Amy manages []
Steve manages [John: 101, Robin: 102, Peter: 103]
Frank manages [Luke: 104, Amy: 105, Steve: 106]

You can see that the code which operates on the List of employees is free of the conditional check before calling directs() method. You can also use this pattern to print an org chart, where each Manager is responsible for printing its reporters, to communicate messages to each employee by defining a receive() method, where each Manager will communicate it further to his directs.




When to use Composite design Pattern in Java?

You should consider using a Composite pattern if you have a hierarchical or tree-like structure like employees in Organization, family members in a dynasty, nodes in an XML document, etc.

Another key thing to remember to find the usage of Composite pattern is the use of instanceof operator if you are receiving an object and instead of directly calling a method on it, checking for a specific type, then Composite is a way to treat them uniformly.

As in this example, if we need to call directs() method on Employee, we can also do that by checking each employee instanceof Manager code. The composite pattern allows you to treat both leaf objects and composite in a uniform way.

This is a useful pattern and can simplify your code on many occasions. If you need more examples or want to learn more about Composite and other Object-Oriented Design Pattern in Java then you can also check out the Design Patterns in Java course on Udemy, one of the best courses to discover modern implementations of classic design patterns in Java. 

Here is a nice UML diagram of Composite Pattern which will help you to understand this pattern better.

composite design pattern explained with UML diagram



That's all about what is the Composite design pattern in Java. You have not only learned how to implement composite design patterns in Java but also when to use Composite patterns and the pros and cons of Composite patterns. It's one of the usage patterns on a Java developer's design pattern armory.

As we have seen, one of the key advantages of this pattern is simple and readable code, which is possible because of treating composite and node objects in a similar fashion.

This same feature is also it's the biggest disadvantage because it allows a client to call composite methods on a node object, which are not meant to be called or don't have valid behavior. As with any design decision, one has to live with this trade-off, if the advantage of composite pattern outweighs the risk of wrong method calls.


Other Java Design Patterns tutorials you may like
  • 5 Free Courses to learn Object Oriented Programming (courses)
  • How to design a Vending Machine in Java? (questions)
  • How to implement a Decorator design pattern in Java? (tutorial)
  • How to use Factory method design pattern in Java? (tutorial)
  • When to use Command Design Pattern in Java (example)
  • 7 Best Courses to learn Design Pattern in Java (courses)
  • How to create thread-safe Singleton in Java (example)
  • Difference between Factory and Abstract Factory Pattern? (example)
  • 7 Best Books to learn the Design Pattern in Java? (books)
  • How to implement the Strategy Design Pattern in Java? (example)
  • Difference between Factory and Dependency Injection Pattern? (answer)
  • 18 Java Design Pattern Interview Questions with Answers (list)
  • Difference between State and Strategy Design Pattern in Java? (answer)
  • 20 System Design Interview Questions (list)
  • 10 OOP Design Principle Every Java developer should learn (solid principle)
  • 5 Free Courses to learn Data Structure and Algorithms (courses)
  • 7 Books to learn System Design for Beginners (System design books)

Thanks a lot for reading this article so far. If you like my explanation of the Composite design pattern in Java and find this article worth your time then please share it with your friends and colleagues. If you have any questions or feedback then please drop a note.

P. S. - If you are an experienced Java programmer and want to learn Design patterns and looking for a free online training course to start with then you can also check out this Java Design Pattern and Architecture free course on Udemy. It's completely free and you just need a free Udemy account to join this course.

1 comment :

Anonymous said...

well done, very well explained.

Post a Comment