Fundamentals 14 min read

Design Pattern #10 – Composite Pattern: Organizing a Group of Objects

The article explains how the Composite pattern solves the pain of handling tree‑like structures—such as orders with nested packages—by providing a uniform component interface that eliminates instanceof checks, discusses transparent vs safe variants, shows real‑world library examples, and outlines when the pattern is appropriate.

Dabaoshi
Dabaoshi
Dabaoshi
Design Pattern #10 – Composite Pattern: Organizing a Group of Objects

1. The Trouble with Tree Structures

In many business domains (file systems, organization charts, DOM trees, etc.) data forms a hierarchy where a "single element" and a "container" can be nested arbitrarily. The example uses an order that contains products and combo packages, some of which themselves contain other items.

Without the Composite pattern, client code must constantly distinguish between leaf objects and containers using instanceof checks and manual recursion, violating the Open/Closed Principle and scattering type‑specific logic throughout the codebase.

2. Composite Pattern – Making Single and Group Look the Same

The core idea is to let both leaves and containers implement a common interface so the client can treat them uniformly.

public interface OrderComponent {
    double getPrice();
    void print(String indent);
}

Leaf implementation (a product) simply returns its own price:

public class Product implements OrderComponent {
    private final String name;
    private final double price;
    public Product(String name, double price) { this.name = name; this.price = price; }
    public double getPrice() { return price; }
    public void print(String indent) {
        System.out.println(indent + "Product:" + name + " ¥" + price);
    }
}

Composite implementation (a combo package) holds a list of OrderComponent children and forwards calls to them:

public class ComboPackage implements OrderComponent {
    private final String name;
    private final List<OrderComponent> children = new ArrayList<>();
    public ComboPackage(String name) { this.name = name; }
    public void add(OrderComponent child) { children.add(child); }
    public double getPrice() {
        double total = 0;
        for (OrderComponent child : children) {
            total += child.getPrice(); // recursion happens automatically
        }
        return total;
    }
    public void print(String indent) {
        System.out.println(indent + "Combo:" + name);
        for (OrderComponent child : children) {
            child.print(indent + "  ");
        }
    }
}

Client code now simply calls getPrice() on any OrderComponent without knowing whether it is a leaf or a container:

ComboPackage lunch = new ComboPackage("Lunch Combo");
 lunch.add(new Product("Burger", 20));
 lunch.add(new Product("Fries", 10));
 ComboPackage drinks = new ComboPackage("Drinks");
 drinks.add(new Product("Coffee", 15));
 lunch.add(drinks);
 System.out.println(lunch.getPrice()); // prints 45

3. Roles and the Beauty of Recursion

The pattern defines three roles:

Component – the abstract interface ( OrderComponent) shared by leaves and composites.

Leaf – concrete class without children ( Product).

Composite – class that holds children and forwards operations ( ComboPackage).

Because the composite stores references to the abstract component ( List<OrderComponent>) rather than concrete leaf types, it can contain both leaves and other composites, enabling unlimited nesting. All operations become simple recursive traversals without explicit if statements.

4. A Key Trade‑off: Transparent vs. Safe Mode

The design decision concerns where to place child‑management methods ( add, remove).

Transparent mode : declare add / remove in the component interface. Leaves must implement them (often as no‑ops or throwing exceptions). This gives a completely uniform interface but pushes runtime errors to execution time.

Safe mode : declare the methods only in the composite class. Leaves cannot be misused at compile time, but the client must first check whether a component is a composite before calling add / remove, re‑introducing type checks.

In practice, transparent mode is used more often because the pattern’s main goal is to hide the distinction between single objects and groups.

5. Real‑World Appearances

Whenever a tree exists, the Composite pattern is present:

Java AWT / Swing component hierarchy (Component, Button, Container, etc.)

DOM tree (Node, Text, Element)

File system abstraction (File as file or directory)

Menu trees, permission trees, organizational charts, nested comments, etc.

6. When to Use the Composite Pattern

Use it if:

The data naturally forms a hierarchical/tree structure.

You want to treat individual objects and compositions uniformly, avoiding instanceof checks.

Adding new leaf or composite types should not require changes to existing traversal logic.

Do not use it for flat, single‑level collections or when element behaviors differ so much that a common interface becomes forced and awkward.

7. Summary

The Composite pattern is the go‑to solution for tree‑like structures. By letting leaves and composites share a common interface, client code can operate on them with complete uniformity, eliminating type discrimination and recursive boilerplate. The pattern offers two variants—transparent (uniform interface) and safe (type‑checked)—with transparent being the more common choice. Classic examples include Swing UI trees, DOM, and file systems. The next article will cover the Facade pattern, which provides a simple front‑door to a complex subsystem.

Composite pattern diagram
Composite pattern diagram
Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

Design PatternsJavaObject-OrientedTree StructureComposite Pattern
Dabaoshi
Written by

Dabaoshi

Practical utilities

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.