Composite

Compose objects into tree structures

Overview

The Composite pattern is a structural design pattern that lets you compose objects into tree structures to represent part-whole hierarchies. Composite lets clients treat individual objects and compositions of objects uniformly.

This pattern makes sense when your core model can be represented as a tree, such as a file system, a GUI component tree, or a corporate hierarchy.

Key Concepts

Component: Interface for all components (leaf and composite)

Leaf: Basic element of a tree that doesn't have sub-elements

Composite: Element that has sub-elements

Client: Works with all components via the base interface

Treats single objects and groups uniformly

Code Example

java
1// Component
2public interface FileSystemObject {
3    void print(String prefix);
4    int getSize();
5}
6
7// Leaf
8public class File implements FileSystemObject {
9    private String name;
10    private int size;
11    
12    public File(String name, int size) {
13        this.name = name;
14        this.size = size;
15    }
16    
17    @Override
18    public void print(String prefix) {
19        System.out.println(prefix + "- File: " + name + " (" + size + "KB)");
20    }
21    
22    @Override
23    public int getSize() {
24        return size;
25    }
26}
27
28// Composite
29import java.util.ArrayList;
30import java.util.List;
31
32public class Directory implements FileSystemObject {
33    private String name;
34    private List<FileSystemObject> children = new ArrayList<>();
35    
36    public Directory(String name) {
37        this.name = name;
38    }
39    
40    public void add(FileSystemObject obj) {
41        children.add(obj);
42    }
43    
44    public void remove(FileSystemObject obj) {
45        children.remove(obj);
46    }
47    
48    @Override
49    public void print(String prefix) {
50        System.out.println(prefix + "+ Dir: " + name);
51        for (FileSystemObject child : children) {
52            child.print(prefix + "  ");
53        }
54    }
55    
56    @Override
57    public int getSize() {
58        int totalSize = 0;
59        for (FileSystemObject child : children) {
60            totalSize += child.getSize();
61        }
62        return totalSize;
63    }
64}
65
66// Client
67public class Main {
68    public static void main(String[] args) {
69        Directory root = new Directory("root");
70        Directory src = new Directory("src");
71        Directory docs = new Directory("docs");
72        
73        File mainJava = new File("Main.java", 10);
74        File utilsJava = new File("Utils.java", 15);
75        File readmeTxt = new File("readme.txt", 2);
76        
77        src.add(mainJava);
78        src.add(utilsJava);
79        docs.add(readmeTxt);
80        
81        root.add(src);
82        root.add(docs);
83        root.add(new File("config.json", 1));
84        
85        System.out.println("Total size: " + root.getSize() + "KB");
86        root.print("");
87    }
88}

The Directory and File both implement FileSystemObject. The Directory can contain both Files and other Directories, and the client treats them the same when calculating sizes or printing.

When to Use

  • When you need to represent part-whole hierarchies (tree structures)

  • When you want clients to be able to ignore the difference between compositions of objects and individual objects

  • For complex UI components, file systems, organizational charts

Advantages

  • Simplifies client code

  • Makes it easier to add new kinds of components

  • Provides flexibility by uniform treatment of objects

💡 Interview Tips

  • Draw the class diagram clearly showing the interface and concrete classes

  • Mention how recursive methods work in Composites (e.g., getSize())

  • File System is the best real-world example to explain

AI Tutor

Ask about the topic

Sign in Required

Please sign in to use the AI tutor

Sign In
Composite - Structural Patterns | LLD | Revise Algo