Introduction
Have you ever worked with hierarchical structures like files and folders, or UI elements inside a layout?
If yes, you’ve already felt the need for the Composite Design Pattern — even if you didn’t know its name. The Composite Pattern lets you treat individual objects and compositions of objects uniformly.
In simple terms:
It allows clients to deal with a single object or a group of objects in the same way.
The core idea
Component
/ \
Leaf Composite
/ \
Leaf Leaf
- Component → defines the common interface for all objects.
- Leaf → represents the end objects (no children).
- Composite → contains child components (can be both leaves and composites).
Real life Example: File System (Files and Folders)
Let’s implement a simple example in Java.
Step 1: Create the FileSystemComponent
interface
interface FileSystemComponent {
void showDetails();
}
This acts as the common interface for both files and folders.
Step 2: Implement the File
class (Leaf)
class File implements FileSystemComponent {
private String name;
public File(String name) {
this.name = name;
}
@Override
public void showDetails() {
System.out.println("File: " + name);
}
}
This is our Leaf — will not have any further nodes (refer the UML diagram).
Step 3: Implement the Directory
class (Composite)
import java.util.ArrayList;
import java.util.List;
class Directory implements FileSystemComponent {
private String name;
private List<FileSystemComponent> children = new ArrayList<>();
public Directory(String name) {
this.name = name;
}
public void addComponent(FileSystemComponent component) {
children.add(component);
}
public void removeComponent(FileSystemComponent component) {
children.remove(component);
}
@Override
public void showDetails() {
System.out.println("Directory: " + name);
for (FileSystemComponent component : children) {
component.showDetails();
}
}
}
This is the Composite — it can hold both File
and Directory
objects.
Step 4: Demo — Build a File System Tree
public class CompositePatternDemo {
public static void main(String[] args) {
File file1 = new File("resume.pdf");
File file2 = new File("photo.png");
File file3 = new File("notes.txt");
Directory documents = new Directory("Documents");
Directory pictures = new Directory("Pictures");
documents.addComponent(file1);
pictures.addComponent(file2);
pictures.addComponent(file3);
Directory home = new Directory("Home");
home.addComponent(documents);
home.addComponent(pictures);
home.showDetails();
}
}
Output
Directory: Home
Directory: Documents
File: resume.pdf
Directory: Pictures
File: photo.png
File: notes.txt
How It Works
The magic here is polymorphism — both File
and Directory
implement FileSystemComponent
.
This means the client (CompositePatternDemo
) doesn’t care whether it’s working with a file or a folder — it just calls showDetails()
!
Comparing this example to the component, leaf and composite analogy, here is summary
Role | Class in Example | Responsibility |
---|---|---|
Component | FileSystemComponent |
Common interface |
Leaf | File |
Represents end object |
Composite | Directory |
Contains child components |
Considerations
- Composite can make the design too general, allowing you to add inappropriate objects.
- Traversal or ordering logic can become complex if the hierarchy is deep.
When to Use It
- You have objects organized in a tree structure (e.g., file systems, organizational charts, menus).
- You want to perform operations on both single objects and groups in the same way.
- You want to simplify client code that deals with complex hierarchies.
Key Benefits
- Simplifies client code dealing with hierarchies
- Encourages consistency across components
- Makes it easy to add new types of components
This is Part 9 of the Java Design Patterns Series.
If you find it insightful, please share your feedback. Also let me know if you have used composite pattern in your projects.
Next Up: Bridge Design Patterns!
Top comments (0)