Skip to content
DevPedia

Structural patternsGuide 11 of 28

Composite

How to work with individual objects and groups of objects through one interface, simplifying how hierarchical structures are handled.

Updated 6 min read

Composite is a structural pattern that lets you compose objects into tree structures and treat an individual object exactly like a composition of those objects.

The problem

AndesShop’s catalog is organized into categories: “Trekking” contains “Footwear” and “Apparel”; “Footwear” contains “Boots” and “Sneakers”; and inside each leaf category there are concrete products. Calculating the total inventory value of “Trekking” means summing the value of every product, no matter how many levels of subcategories sit in between. If the calculation code has to explicitly distinguish between “this is a product” and “this is a category with subcategories”, it ends up with hand-written recursive traversals duplicated everywhere the tree needs walking.

The solution

Composite defines a common interface (CatalogNode) for both leaf nodes (products) and composite nodes (categories), with an operation like getTotalValue(). A product simply returns its own value; a category forwards the question to each of its children and sums the results — without the client code ever needing to know whether it’s standing on a leaf or on a branch of the tree.

The structure of Composite: leaf and composite share the same interface, and a composite contains zero or more nodes, which can themselves be composites.

Example in Java

interface CatalogNode {
    double getTotalValue();
}

// Leaf: a concrete product
class Product implements CatalogNode {
    private final double price;
    private final int stock;

    public Product(double price, int stock) {
        this.price = price;
        this.stock = stock;
    }

    public double getTotalValue() {
        return price * stock;
    }
}

// Composite: a category, which can hold products or other categories
class Category implements CatalogNode {
    private final List<CatalogNode> children = new ArrayList<>();

    public void add(CatalogNode node) {
        children.add(node);
    }

    public double getTotalValue() {
        double total = 0;
        for (CatalogNode child : children) {
            total += child.getTotalValue(); // it doesn't care whether it's a Product or a Category
        }
        return total;
    }
}
Category footwear = new Category();
footwear.add(new Product(120.0, 30));  // boots
footwear.add(new Product(80.0, 50));   // sneakers

Category trekking = new Category();
trekking.add(footwear);
trekking.add(new Product(200.0, 15)); // a jacket, directly under Trekking

System.out.println(trekking.getTotalValue()); // sums the whole tree, without distinguishing levels

When to use it

  • When your domain naturally has a tree structure (categories and products, folders and files, nested visual components).
  • When you want the client code to treat individual objects and compositions of objects in exactly the same way.

When to avoid it

If your model isn’t genuinely hierarchical, forcing a tree structure where there isn’t one adds complexity for nothing.

Benefits and drawbacks

BenefitsDrawbacks
The client code works with leaves and compositions identically, because both implement CatalogNodeIt can be hard to restrict which child types are valid in each branch of the tree
Follows the open/closed principle: adding a new node type doesn’t break existing codeThe common interface sometimes ends up too generic
Simplifies the client code, which no longer needs conditionals by node type

Relationship with other patterns

  • Decorator shares with Composite the idea of wrapping objects recursively, but Decorator always wraps a single object, without branching into several children.
  • Iterator combines naturally with Composite to traverse the tree without exposing its structure.
  • Visitor is often used alongside Composite to apply operations to the whole tree without cluttering the Product and Category classes with every new operation.

Share this guide

Search by concept, pattern or practice.