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
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