Decorator vs Inheritance: When to Use Each
Fast recall
Quick revision
Core answer
Interview-ready guide
Interview answer
Use Decorator when you need optional behaviors that can combine in different ways, or when inheritance would create too many classes.
Use inheritance when you're modeling a true type hierarchy with a stable is-a relationship. Here's the key difference: inheritance is compile-time and fixed, Decorator is runtime and flexible. Say you've got a notification system.
You might send notifications by email, SMS, or push. Those are the base types—that's inheritance. But each notification might need encryption, compression, or logging—those are optional and can combine.
With inheritance, you'd need EncryptedEmailNotifier, CompressedEmailNotifier, EncryptedCompressedEmailNotifier, plus all the SMS and push variants. That's exponential growth: three base types times eight combinations equals twenty-four classes. With Decorator, you have three base types plus three decorators—six classes total.
You wrap notifications at runtime based on what each user needs. The math matters. If you have N optional features that can combine, inheritance needs 2 to the N classes.
Decorator needs N plus one. For three features, that's eight versus four. For five features, it's thirty-two versus six.
Decorator scales linearly; inheritance scales exponentially. One mistake freshers make is using inheritance for everything because it's simpler upfront. But when requirements change and you need new combinations, you're stuck adding more subclasses.
Decorator keeps your classes open for extension but closed for modification—you add new decorators without touching existing code.
Decorator vs Inheritance: When to Use Each
Direct Answer
Use Decorator when you need optional, combinable behaviors at runtime or when inheritance would cause class explosion. Use inheritance when the relationship is a stable is-a with fixed behavior and you're modeling true type hierarchy, not adding responsibilities.
Code Example
// INHERITANCE: 3 optional features -> up to 8 subclasses (2^3)
interface Notifier { void send(String m); }
class Email implements Notifier { public void send(String m){ System.out.println("email " + m); } }
// EncryptedEmail, CompressedEmail, EncryptedCompressedEmail, ... class explosion
// DECORATOR: 3 features -> 4 classes (base + 3), composed at runtime
abstract class NotifierDecorator implements Notifier {
protected final Notifier inner;
NotifierDecorator(Notifier n){ this.inner = n; }
}
class Encrypted extends NotifierDecorator {
Encrypted(Notifier n){ super(n); }
public void send(String m){ inner.send("[enc]" + m); }
}
class Logged extends NotifierDecorator {
Logged(Notifier n){ super(n); }
public void send(String m){ System.out.println("log"); inner.send(m); }
}
// new Logged(new Encrypted(new Email())) - add features without new subclasses.
Common Mistakes & Pitfalls
- Using inheritance for optional features: Freshers create subclasses like OrderWithLogging, OrderWithCaching, OrderWithLoggingAndCaching—this creates exponential class growth and makes it impossible to add combinations not anticipated upfront.
- Using Decorator for type hierarchies: Creating VehicleDecorator to wrap Car, Truck, Motorcycle misses that these are distinct types with different contracts—inheritance is correct here because they model an is-a relationship, not optional behaviors.
- Overcomplicating simple cases: If you only have one or two features that don't combine and are fixed at creation, inheritance is cleaner—Decorator adds wrapping boilerplate without benefit.
- Ignoring the Open-Closed Principle: Using inheritance for every extension means modifying the class hierarchy when requirements change—Decorator lets you add new decorators without touching existing code.
Check your understanding
Answer these without looking back at the article.
- What is the difference between Decorator and Proxy patterns?
- How does Decorator relate to the open/closed principle?
Looking for a structured roadmap?
Every module on this page is also part of the full Java backend interview track.