The Composite pattern gives an individual object and a group of objects the same interface. An account application can then ask either one account or an entire portfolio for its balance through one method.
Compose objects into tree structures to represent part-whole hierarchies. Composite lets clients treat individual objects and compositions of objects uniformly.
Use Composite when an operation makes sense for both a single item and a group of those items. Here, balanceCents() works on an Account and on a Portfolio that contains accounts or smaller portfolios.
1. How the Composite Pattern Works
A component declares the operation available at every level. A leaf handles it for one item, while a composite holds other components and combines their results. The client calls the component interface without checking which kind of object it received.
| Participant | Responsibility |
|---|---|
| Component | Declares the operation shared by individual items and groups. |
| Leaf | Performs the operation for one item and has no children. |
| Composite | Holds components and performs the operation using its children. |
| Client | Calls the shared operation on a component. |
A composite can contain another composite because both satisfy the same component interface. When the group asks each child to perform the operation, the request continues through nested groups until it reaches leaves. This repeated call on smaller parts of the same structure is recursion.
2. Composite Pattern in Action
Our example is a balance view in an account application. The view needs to show the balance of one account, a deposit portfolio, or the customer’s whole portfolio. Balances use whole cents so the example does not depend on floating-point arithmetic.
| Example type | Pattern role | Responsibility |
|---|---|---|
| AccountComponent | Component | Declares balanceCents(). |
| Account | Leaf | Returns its stored balance. |
| Portfolio | Composite | Sums the balances returned by its child components. |
| CompositeDemo | Client | Builds the hierarchy and requests each balance. |
The deposit portfolio contains two accounts. The customer portfolio contains a savings account and the deposit portfolio. When the client calls balanceCents() on the customer portfolio, it asks both children for their balances. The deposit portfolio makes the same request of its two accounts. Each result returns to its parent, which adds the values.
3. Composite Pattern Implementation
The shared AccountComponent interface declares only the operation that both an account and a portfolio can perform. Account stores one balance and returns it through the record’s generated accessor.
interface AccountComponent {
long balanceCents();
}
record Account(long balanceCents) implements AccountComponent {
}
Portfolio accepts its children at construction. List.copyOf() returns an unmodifiable list, so changing a modifiable input list later cannot change this portfolio’s membership. The method does not copy the child objects themselves.
final class Portfolio implements AccountComponent {
private final List<AccountComponent> children;
Portfolio(List<AccountComponent> children) {
this.children = List.copyOf(children);
}
@Override
public long balanceCents() {
long total = 0;
for (AccountComponent child : children) {
total = Math.addExact(total, child.balanceCents());
}
return total;
}
}
An Account returns its own value. A Portfolio asks each child for a value, including a child that is another portfolio. Math.addExact() throws ArithmeticException if the sum exceeds the range of long, instead of silently wrapping to an incorrect balance. Child management stays with Portfolio; an account has no meaningful addChild() operation. The article excerpts omit the package, import, and demo entry point; the complete runnable source supplies them.
4. Demo
The client builds a nested portfolio, then requests balances through AccountComponent references. It also uses one account twice to show how membership affects the total and asks for a sum that overflows.
AccountComponent savings = new Account(20_000);
AccountComponent deposits = new Portfolio(List.of(
new Account(10_000), new Account(15_000)));
AccountComponent customer = new Portfolio(List.of(savings, deposits));
System.out.println("Savings: " + savings.balanceCents());
System.out.println("Deposits: " + deposits.balanceCents());
System.out.println("Customer: " + customer.balanceCents());
AccountComponent repeated = new Portfolio(List.of(savings, savings));
System.out.println("Repeated account: " + repeated.balanceCents());
try {
new Portfolio(List.of(new Account(Long.MAX_VALUE), new Account(1)))
.balanceCents();
} catch (ArithmeticException e) {
System.out.println("Overflow rejected: " + e.getMessage());
}
From the repository root, compile and run the complete class:
javac -d target/composite-demo -sourcepath src/main/java src/main/java/com/howtodoinjava/patterns/structural/composite/CompositeDemo.java
java -cp target/composite-demo com.howtodoinjava.patterns.structural.composite.CompositeDemo
Savings: 20000
Deposits: 25000
Customer: 45000
Repeated account: 40000
Overflow rejected: long overflow
The first three lines show one account, a two-account group and an outer group containing both. Reusing the savings account makes the fourth total twice its value; the final line shows checked addition rejecting a value outside long‘s range.
5. Ownership and Limits
A shared interface does not enforce a tree. Our code allows the same Account object in multiple branches, so a balance calculated across both branches counts it twice. An application that requires each account to belong to one portfolio must enforce that ownership rule when building its hierarchy.
The construction-only list prevents callers from adding a child after a Portfolio is built. It does not prove that every possible AccountComponent implementation is acyclic. A mutable composite must reject a child that is itself or one of its ancestors; otherwise the recursive calculation may continue until the call stack is exhausted. Very deep valid nesting can also exhaust the stack, so a large or untrusted hierarchy may need iterative traversal.
6. Similar Patterns
| Pattern | Choose it when |
|---|---|
| Composite | An item and a group of items need the same operation in a hierarchy. |
| Decorator | One wrapper adds behavior to an object through the same interface; it does not model a collection of children. |
| Visitor | A stable object structure needs new operations without putting each operation in every element class. |
Composite answers how to represent and use the hierarchy; Visitor answers where to put additional operations on its elements. The patterns can be used together.
7. FAQs
Does every component need child-management methods?
No. Our component has only balanceCents(). Putting addChild() on the interface would require Account to expose an operation it cannot perform. A mutable design can put child-management methods on Portfolio alone.
Must a composite be mutable?
No. This example supplies all children when constructing Portfolio. A mutable composite is useful when membership changes, but then it needs clear rules for duplicate children and cycles.
Can a composite contain other composites?
Yes. That is what lets a group contain smaller groups. Each nested Portfolio implements AccountComponent, so its parent calls the same balanceCents() method used for an Account.
8. Conclusion
Composite fits a part-and-whole hierarchy when the client should make the same request of an individual item and a group. The shared interface simplifies the call; the composite defines how child results combine. Decide ownership and cycle rules for the application rather than assuming the pattern supplies them.
Happy Learning!
The description for composite pattern and example code given, does not really match as per me. User having multiple accounts it typical one to many relationship & not a tree structure per say. Directory structure in file system implementations or menu in websites would have been better example as you’ve earlier suggested.
please , send a example on both flyweight and composite design patterns with same Account example .