Composite Design Pattern example in Java
Imagine you are building a project management system where tasks can be either simple tasks or a collection of tasks (subtasks) forming a larger task.
1. Task (Component)
- Represents the common interface for both simple tasks and task lists.
- Defines methods such as
getTitle()
,setTitle()
, anddisplay()
.
Java
// Component public interface Task { String getTitle(); void setTitle(String title); void display(); } |
2. SimpleTask (Leaf)
- Represents an individual task with a title.
- Implements the
Task
interface.
Java
// Leaf public class SimpleTask implements Task { private String title; public SimpleTask(String title) { this .title = title; } @Override public String getTitle() { return title; } @Override public void setTitle(String title) { this .title = title; } @Override public void display() { System.out.println( "Simple Task: " + title); } } |
3. TaskList (Composite)
- Represents a collection of tasks, which can include both simple tasks and other task lists.
- Implements the
Task
interface but also has a list of tasks (List<Task>
). - Defines methods to add, remove, and display tasks.
Java
import java.util.ArrayList; import java.util.List; // Composite public class TaskList implements Task { private String title; private List<Task> tasks; public TaskList(String title) { this .title = title; this .tasks = new ArrayList<>(); } @Override public String getTitle() { return title; } @Override public void setTitle(String title) { this .title = title; } public void addTask(Task task) { tasks.add(task); } public void removeTask(Task task) { tasks.remove(task); } @Override public void display() { System.out.println( "Task List: " + title); for (Task task : tasks) { task.display(); } } } |
4. TaskManagementApp (Client)
- Represents the application that uses the Composite Design Pattern to manage tasks.
- It creates a mix of simple tasks and task lists, showcasing how the Composite pattern allows treating both individual tasks and task collections uniformly.
- The created tasks are displayed in a hierarchical structure to illustrate the pattern’s flexibility and uniform handling of different task types.
Java
// Client public class TaskManagementApp { public static void main(String[] args) { // Creating simple tasks Task simpleTask1 = new SimpleTask( "Complete Coding" ); Task simpleTask2 = new SimpleTask( "Write Documentation" ); // Creating a task list TaskList projectTasks = new TaskList( "Project Tasks" ); projectTasks.addTask(simpleTask1); projectTasks.addTask(simpleTask2); // Nested task list TaskList phase1Tasks = new TaskList( "Phase 1 Tasks" ); phase1Tasks.addTask( new SimpleTask( "Design" )); phase1Tasks.addTask( new SimpleTask( "Implementation" )); projectTasks.addTask(phase1Tasks); // Displaying tasks projectTasks.display(); } } |
Complete code for the above example:
This code includes the Task
, SimpleTask
, TaskList
, and TaskManagementApp
classes. It demonstrates the Composite Design Pattern for organizing tasks in a project management system.
Java
import java.util.ArrayList; import java.util.List; // Component interface Task { String getTitle(); void setTitle(String title); void display(); } // Leaf class SimpleTask implements Task { private String title; public SimpleTask(String title) { this .title = title; } @Override public String getTitle() { return title; } @Override public void setTitle(String title) { this .title = title; } @Override public void display() { System.out.println( "Simple Task: " + title); } } // Composite class TaskList implements Task { private String title; private List<Task> tasks; public TaskList(String title) { this .title = title; this .tasks = new ArrayList<>(); } @Override public String getTitle() { return title; } @Override public void setTitle(String title) { this .title = title; } public void addTask(Task task) { tasks.add(task); } public void removeTask(Task task) { tasks.remove(task); } @Override public void display() { System.out.println( "Task List: " + title); for (Task task : tasks) { task.display(); } } } // Client public class TaskManagementApp { public static void main(String[] args) { // Creating simple tasks Task simpleTask1 = new SimpleTask( "Complete Coding" ); Task simpleTask2 = new SimpleTask( "Write Documentation" ); // Creating a task list TaskList projectTasks = new TaskList( "Project Tasks" ); projectTasks.addTask(simpleTask1); projectTasks.addTask(simpleTask2); // Nested task list TaskList phase1Tasks = new TaskList( "Phase 1 Tasks" ); phase1Tasks.addTask( new SimpleTask( "Design" )); phase1Tasks.addTask( new SimpleTask( "Implementation" )); projectTasks.addTask(phase1Tasks); // Displaying tasks projectTasks.display(); } } |
Task List: Project Tasks Simple Task: Complete Coding Simple Task: Write Documentation Task List: Phase 1 Tasks Simple Task: Design Simple Task: Implementation
Composite Design Pattern in Java
The Composite Design Pattern is a structural design pattern that lets you compose objects into tree-like structures to represent part-whole hierarchies. It allows clients to treat individual objects and compositions of objects uniformly. In other words, whether dealing with a single object or a group of objects (composite), clients can use them interchangeably.
As described by the Gang of four, “Compose objects into tree structure to represent part-whole hierarchies. Composite lets client treat individual objects and compositions of objects uniformly”.
The key concept is that you can manipulate a single instance of the object just as you would manipulate a group of them. The operations you can perform on all the composite objects often have the least common denominator relationship.
Important Topics for the Composite Design Pattern in Java
- Components of Composite Design Pattern
- Composite Design Pattern example in Java
- Why do we need Composite Design Pattern?
- When to use Composite Design Pattern?
- When not to use Composite Design Pattern?