Connect with me
Structural Design Pattern: Composite
The Composite Design Pattern allows objects to be organized in a tree hierarchy, enabling uniform treatment of individual and grouped elements.

This article is part of a series exploring design patterns using the Java programming language. The goal of this series is to help readers develop a solid understanding of design patterns while also sharing real-world examples from actual codebases that make use of these patterns.
In this article, we’ll be discussing the Composite pattern.
Symbols for better navigation:
🤔 Hypothetical Scenario/Imagination
⚠️ Warning
👉 Point to note
📝 Common Understanding
Composite Pattern
Composite pattern is used to represent objects in a tree hierarchy.
In a composite pattern, the objects are created as subclasses of the same abstract class template.
A very good example of this is Java’s AWT library, which is used to draw UI elements. The library’s top-level component creates two kinds of composites 👉
- Container: Holds the UI elements.
- Leaf: Represents basic UI elements like buttons, text boxes, etc.

Recipe to cook the Composite Pattern for objects
⚠️ Objects cannot be converted to composites.
Hence, we have to start by building them from scratch.
- Create an abstract component class template, which will act as the parent component for all objects.
- Create different object types that extend the component class.
- Relate objects to each other by composing these components as children of each other.
Let’s create our abstract component class template.
public abstract class Component {
String name;
String url;
List<Component> children = new ArrayList<>();
public String getName() {
return name;
}
public String getUrl() {
return url;
}
public void add(Component c) {
throw new UnsupportedOperationException("This operation is not supported");
}
public void remove(Component c) {
throw new UnsupportedOperationException("This operation is not supported");
}
public abstract String toString();
}Now, let’s create our first object based on the component.
public class Parent extends Component {
public Parent(String name, String url) {
this.name = name;
this.url = url;
}
@Override
public void add(Component c) {
this.children.add(c);
}
@Override
public void remove(Component c) {
this.children.remove(c);
}
}Now, we’ll create one more component as follows.
public class Item extends Component {
public Item(String name, String url) {
this.name = name;
this.url = url;
}
@Override
public String toString() {
return this.name;
}
// ... override add/remove methods if required
}Finally, we can use this as follows.
public class CompositeDesignPatternDemo {
public static void main() {
Parent par = new Parent("parent 1", "http://localhost");
Item item1 = new Item("item 1", "http://localhost/hello");
Item item2 = new Item("item 2", "http://localhost/world");
par.add(item1);
par.add(item2);
}
}Case-Study
🤔 Imagine we’re designing a UI library, just like Java’s AWT.
You start by creating basic elements like Button, Label, TextField, etc. Each of these can draw itself on the screen.
Now, we want to group several elements together, say, to create a Container that contains a Label and a Button.
So we create another element to contain these elements.
So far, so good.
⚠️ The challenge begins here:
- We have to write separate logic for both the container and the individual elements to render on the screen.
- Some effects, like colour, layout, enable/disable, etc., for the UI elements will remain the same. But how do we write logic in a manner that can apply uniformly to all types of elements?
Without a structured design, you might end up writing separate logic for individual components and for groups.
👉 Here, we can think of using the Composite Design Pattern.
We’ll start by creating the base template UIComponent for all the elements.t for all the elements.
public abstract class UIComponent {
private List<UIComponent> children;
public void add(UIComponent comp) {
throw new Exception("method not implemented");
}
public void remove(UIComponent comp) {
throw new Exception("method not implemented");
}
abstract void render();
}
Now, we’ll start with our Container object as follows.
class Container implements UIComponent {
public void add(UIComponent component) {
children.add(component);
}
public void remove(UIComponent component) {
children.remove(component);
}
@Override
public void render() {
System.out.println("Rendering Panel:");
for (UIComponent child : children) {
child.render(); // delegate render call to children
}
}
}Finally, let’s create all our basic UI elements like buttons, labels, etc.
// Leaf
class Button implements UIComponent {
private String label;
public Button(String label) {
this.label = label;
}
@Override
public void render() {
System.out.println("Rendering Button: " + label);
}
}
// Leaf
class Label implements UIComponent {
private String text;
public Label(String text) {
this.text = text;
}
@Override
public void render() {
System.out.println("Rendering Label: " + text);
}
}With this design, drawing a complex UI becomes very easy! Take a look.
public class CompositeExample {
public static void main(String[] args) {
// Create individual components
Button okButton = new Button("OK");
Label messageLabel = new Label("Welcome to the app");
// Create a composite component (Panel)
Panel mainPanel = new Panel();
mainPanel.add(messageLabel);
mainPanel.add(okButton);
// Client treats everything as a UIComponent
mainPanel.render();
}
}Real-World Use Case of Composite
The File in the Java.io package of Java JDK mimics the file system of the operating system.
A directory can contain files or other directories; both should be treated uniformly.
- Directory: composite (can contain files and subdirectories)
- FileSystemNode: abstract component.
- File: leaf
The File can then be used as a directory to contain more files, as shown in the code example.

Up Next in the Series
Subscribe to my newsletter today!




