When would you use the Decorator pattern instead of inheritance?
Design patternsMid-level
In shortWhen behaviors like caching, logging, retries or metrics should be combined freely around an object without changing it. Decorators wrap the same interface and compose; inheritance needs a subclass per combination and is fragile when the base class calls its own methods.
Model answer
Inheritance adds behavior at compile time, one combination per class: CachedRepository, LoggingCachedRepository, RetryingLoggingCachedRepository… A decorator implements the same interface as the object it wraps, adds one behavior, and delegates to the inner object, so behaviors compose at runtime:
val repo: ProductRepository = Logging(Caching(Retrying(ApiProductRepository(api))))
Use decorators when:
- several cross-cutting behaviors should combine freely (cache, log, retry, metrics, auth),
- you can’t or shouldn’t modify the original (third-party, final, shared),
- you want each behavior testable alone with a fake inner object.
Things to get right:
- Order is semantics: a cache outside a logger hides hits from the log; a retry outside a timeout gives each attempt its own timeout.
- Every method is wrapped: a generic retry around an interface that includes
charge()can double-charge on timeouts. - Composition over inheritance: subclassing a concrete class to “decorate” it breaks when the base class calls its own overridable methods (
HashSet.addAllcallingadd), the fragile base class problem. Kotlin’sbydelegation avoids it but forwards un-overridden methods straight to the inner object.
What they're looking for
The combinatorial-subclass problem, how decorators delegate and compose, real examples (Java I/O, OkHttp interceptors, SwiftUI modifiers, Spring proxies), and the subtleties of ordering and of non-idempotent operations. Bonus for the fragile base class problem.
Common mistakes
- Describing a decorator that doesn't share the wrapped object's interface.
- Ignoring that wrapper order changes behavior.
- Wrapping a payment API in a generic retry decorator.