Chaturmind
LearnDSASystem DesignInterview PrepDevOpsEngineering GrowthBlog
Start learning
Chaturmind

Structured learning paths for engineers who want to go deep. Written by practitioners.

Learn

  • Java
  • DSA
  • System Design
  • Spring Boot
  • AI / ML
  • DevOps
  • Engineering Growth
  • Java Interview Prep

Company

  • Blog
  • Contact

Legal

  • Privacy Policy
  • Terms of Service

© 2026 Chaturmind. All rights reserved.

Built for engineers who want to go deep.


← Java Interview Prep: 5–8 Years

Advanced Core Java

  • Advanced OOP & Design Scenarios — Interview Questions
  • Advanced Concurrency, Collections & Memory — Interview Questions
  • Modern Java Language Features & Annotations — Interview Questions
  • Class Loading, Reflection, Serialization & Idioms — Interview Questions

Java Design Patterns in Depth

  • Design Patterns Overview & Singleton — Interview Questions
  • Factory & Abstract Factory Patterns — Interview Questions
  • Builder & Prototype Patterns — Interview Questions
  • Adapter & Bridge Patterns — Interview Questions
  • Composite & Decorator Patterns — Interview Questions
  • Facade & Proxy Patterns — Interview Questions
  • Chain of Responsibility & Observer Patterns — Interview Questions
  • Strategy & Template Method Patterns — Interview Questions
  • Command Pattern — Interview Questions

Advanced Spring Boot

  • Logging, Configuration & Actuator (Advanced) — Interview Questions
  • Transactions, Multiple Datasources & Query Tuning — Interview Questions
  • Validation & REST API Design (Advanced) — Interview Questions
  • Reactive, Async & Scheduling in Spring Boot — Interview Questions
  • Deployment, High Availability, Scaling & Caching — Interview Questions
Chaturmind
← Java Interview Prep: 5–8 Years

Advanced Core Java

  • Advanced OOP & Design Scenarios — Interview Questions
  • Advanced Concurrency, Collections & Memory — Interview Questions
  • Modern Java Language Features & Annotations — Interview Questions
  • Class Loading, Reflection, Serialization & Idioms — Interview Questions

Java Design Patterns in Depth

  • Design Patterns Overview & Singleton — Interview Questions
  • Factory & Abstract Factory Patterns — Interview Questions
  • Builder & Prototype Patterns — Interview Questions
  • Adapter & Bridge Patterns — Interview Questions
  • Composite & Decorator Patterns — Interview Questions
  • Facade & Proxy Patterns — Interview Questions
  • Chain of Responsibility & Observer Patterns — Interview Questions
  • Strategy & Template Method Patterns — Interview Questions
  • Command Pattern — Interview Questions

Advanced Spring Boot

  • Logging, Configuration & Actuator (Advanced) — Interview Questions
  • Transactions, Multiple Datasources & Query Tuning — Interview Questions
  • Validation & REST API Design (Advanced) — Interview Questions
  • Reactive, Async & Scheduling in Spring Boot — Interview Questions
  • Deployment, High Availability, Scaling & Caching — Interview Questions
HomeLearnJava Interview PrepJava Interview Prep: 5–8 YearsJava Design Patterns in Depth
✓ FreeAdvanced· 7 min read

Composite & Decorator Patterns — Interview Questions

Composite for part-whole hierarchies — purpose, tree modelling, how it simplifies hierarchical data, benefits and limitations (transparency vs safety), Java implementation — and Decorator — dynamic behaviour vs inheritance, implementation, advantages, real examples (I/O streams, HTTP clients), and why it's flexible.

Published September 25, 2026


How to use this lesson

Composite and Decorator both rely on recursive composition through a shared interface. Composite builds trees (one-to-many). Decorator builds chains (one-to-one wrappers). Tie both to real code you've touched, such as java.io streams, UI trees, pricing rules or Spring's ClientHttpRequestInterceptor.

Q1. What is the Composite pattern's purpose?

Short answer: Composite lets you build tree structures of objects, and treat individual objects (leaves) and groups (composites) through the same interface. Clients call operation() on any node, and composites forward the call to their children recursively.

Learn it in depth → Composite & Proxy

Q2. What is the Decorator pattern's purpose?

Short answer: Decorator adds responsibilities to individual objects at runtime, by wrapping them in objects with the same interface. Each wrapper does its extra work before or after delegating. Decorators can be stacked, and apply only to the objects you wrap, not to every instance of the class.

Learn it in depth → Decorator Pattern

Q3. What is the Composite pattern, and when is it most useful?

Short answer: It's most useful for part-whole hierarchies, where clients shouldn't care whether they hold one item or a group:

  • file systems;
  • UI component trees;
  • organisation charts;
  • bills of materials;
  • nested menu or category structures;
  • rule trees (AND/OR conditions);
  • pricing bundles containing products and sub-bundles.

Q4. Give an example of using Composite to model a tree.

Short answer: A product-bundle pricing tree: a bundle's price is the sum of its children, which are either products or nested bundles.

public sealed interface CatalogItem permits Product, Bundle {
    BigDecimal price();
    String name();
}
public record Product(String name, BigDecimal price) implements CatalogItem { }

public record Bundle(String name, List<CatalogItem> items, BigDecimal discountPct) implements CatalogItem {
    public Bundle { items = List.copyOf(items); }
    public BigDecimal price() {
        BigDecimal total = items.stream().map(CatalogItem::price).reduce(BigDecimal.ZERO, BigDecimal::add);   // recursion
        return total.multiply(BigDecimal.ONE.subtract(discountPct.movePointLeft(2)));
    }
}

CatalogItem office = new Bundle("Office Starter",
        List.of(new Product("Laptop", new BigDecimal("55000")),
                new Bundle("Accessories", List.of(new Product("Mouse", new BigDecimal("900")),
                                                  new Product("Bag", new BigDecimal("1500"))), BigDecimal.ZERO)),
        new BigDecimal("10"));
office.price();                                  // the client never checks leaf vs composite

Q5. How does Composite simplify working with hierarchical data?

Short answer: Client code applies one operation to the root, and recursion handles the depth: no instanceof checks, and no manual traversal logic scattered around. Totals, rendering, searching, validation and permissions all become methods on the component, and adding new node types doesn't change the clients.

Key points to cover:

  • For operations that don't belong inside the nodes (exporting to different formats), combine Composite with Visitor, or with pattern matching over a sealed hierarchy.

Q6. What are the benefits and limitations of Composite?

Short answer:

  • Benefits:
    • Uniform treatment of leaves and composites.
    • Recursive operations with simple client code.
    • Easy to add node types.
    • It maps naturally onto JSON and XML trees.
  • Limitations:
    • Transparency vs safety: putting add/remove on the common interface lets clients call add on a leaf, where it throws. Putting them only on the composite forces type checks. Choose deliberately.
    • It's hard to restrict which children are allowed (a folder may not contain a drive).
    • Deep trees mean recursion depth and performance concerns.
    • Operations over huge trees may need caching of aggregates.
    • Cycles must be prevented.

Q7. How do you implement Composite in Java?

Short answer:

  1. Define a Component interface with the common operations.
  2. Implement Leaf classes.
  3. Implement a Composite that holds a List<Component>, delegates operations to its children, and provides add/remove.

The "safe" variant keeps the child management on the composite only.

public interface FileNode { long size(); String name(); }
public record FileLeaf(String name, long size) implements FileNode { }
public final class Folder implements FileNode {
    private final String name; private final List<FileNode> children = new ArrayList<>();
    public Folder(String name) { this.name = name; }
    public Folder add(FileNode n) { children.add(n); return this; }                  // only on the composite (safe)
    public long size() { return children.stream().mapToLong(FileNode::size).sum(); }
    public String name() { return name; }
}

Q8. What is the Decorator pattern, and how does it differ from inheritance?

Short answer: Inheritance adds behaviour statically, to every instance of the subclass. To combine features, you need a subclass for each combination: that's a class explosion. Decorator adds behaviour dynamically, per object, by composition. You combine features by stacking wrappers in any order, at runtime, without touching the original class, and each decorator stays small and single-purpose.

Q9. How do you implement a Decorator in Java?

Short answer: Implement the same interface as the component, hold a reference to the wrapped component, and delegate, adding behaviour around the call. An abstract base decorator can forward everything by default.

public interface QuoteService { BigDecimal quote(String sku); }

public final class CachingQuoteService implements QuoteService {                 // decorator 1
    private final QuoteService delegate; private final Map<String, BigDecimal> cache = new ConcurrentHashMap<>();
    public CachingQuoteService(QuoteService d) { this.delegate = d; }
    public BigDecimal quote(String sku) { return cache.computeIfAbsent(sku, delegate::quote); }
}
public final class TimedQuoteService implements QuoteService {                   // decorator 2
    private final QuoteService delegate; private final MeterRegistry meters;
    public TimedQuoteService(QuoteService d, MeterRegistry m) { this.delegate = d; this.meters = m; }
    public BigDecimal quote(String sku) { return meters.timer("quote.latency").record(() -> delegate.quote(sku)); }
}

QuoteService service = new TimedQuoteService(new CachingQuoteService(new PricingApiQuoteService()), meters);

Key points to cover:

  • Order matters. Timing outside the cache measures cache hits too. Timing inside it measures only real calls.

Q10. What are the advantages of Decorator for extending behaviour?

Short answer:

  • The Open/Closed principle: new behaviour means new decorators, with no changes to existing classes.
  • The Single Responsibility principle: each concern (caching, retries, logging, metrics, encryption) lives in its own class.
  • Runtime composition through configuration.
  • It avoids subclass explosions.
  • Reusable across implementations of the interface.

Drawbacks:

  • Many small objects, and deep stacks when debugging.
  • Identity checks (==) and instanceof see the wrapper, not the core.
  • Order-dependent behaviour.
  • Wide interfaces are tedious to wrap. Dynamic proxies or AOP help there.

Q11. Give real-world examples of the Decorator pattern.

Short answer:

  • java.io: new BufferedReader(new InputStreamReader(new GZIPInputStream(new FileInputStream(f)))). Each layer adds buffering, decoding or decompression.
  • Collections.unmodifiableList, synchronizedMap: add restrictions or synchronisation to an existing collection.
  • HTTP clients: RestClient/RestTemplate interceptors (auth headers, logging, retries), and servlet filters that wrap the request and response.
  • Spring: TransactionAwareDataSourceProxy, LazyConnectionDataSourceProxy, and bean post-processors wrapping beans. These are technically proxies that act as decorators.
  • The classic coffee and add-ons example: each add-on wraps the beverage, and adds cost and description.

Q12. How does Decorator promote flexibility in extending behaviour?

Short answer: Behaviours become independent, composable units, assembled per object, per environment, at runtime:

  • add retries only for remote clients;
  • add caching only in production;
  • add encryption only for sensitive streams;
  • reorder or remove layers without touching the core or the other decorators.

Configuration code, or a DI container, builds the right stack, which keeps business classes free of cross-cutting clutter.

Follow-up questions this topic invites — and their answers

Q: Decorator vs Proxy? A: Both wrap an object with the same interface. A decorator adds behaviour, is usually stacked, and is chosen by the client. A proxy controls access (lazy loading, remote, security, caching), and often manages the real object's lifecycle. The client may not know it's there.

Q: Decorator vs AOP? A: AOP applies decorator-like behaviour across many beans declaratively (through pointcuts and proxies). Hand-written decorators are explicit and typed, and suit a few specific interfaces.

Q: How do you avoid writing delegation boilerplate for large interfaces? A: Extend an abstract forwarding decorator, use Java dynamic proxies (Proxy.newProxyInstance), or apply AOP. For JDK types, use the existing wrapper classes (FilterInputStream, HttpServletRequestWrapper).

Q: Composite vs Decorator structurally? A: A composite holds many children, and aggregates their results. A decorator holds exactly one wrapped component, and enhances it.

Previous

Adapter & Bridge Patterns — Interview Questions

Next

Facade & Proxy Patterns — Interview Questions

AI Tutor

Lesson: Composite & Decorator Patterns — Interview Questions

Quick actions

AI responses can be inaccurate. Verify critical information.