The Decorator pattern is implemented by having a decorator class implement the same interface as the object it wraps, hold a reference to that wrapped object, and add behavior before or after delegating to it. This lets you layer new behavior onto an object without modifying its class or using inheritance.
Key Points: • Define a common Component interface implemented by both the base class and all decorators. • The concrete component provides the core behavior; decorators wrap a Component reference. • Each decorator's method calls the wrapped component's method and adds behavior before/after that call. • Decorators can be stacked, since a decorator is itself a Component and can wrap another decorator. • This avoids a combinatorial subclass explosion for every possible combination of added behaviors.
Example: A InputStream chain like new BufferedInputStream(new FileInputStream("file.txt")) is a real-world use of Decorator baked into the Java standard library.
Code Example:
interface Coffee {
double cost();
}
class SimpleCoffee implements Coffee {
public double cost() { return 2.0; }
}
abstract class CoffeeDecorator implements Coffee {
protected Coffee wrapped;
CoffeeDecorator(Coffee wrapped) { this.wrapped = wrapped; }
}
class MilkDecorator extends CoffeeDecorator {
MilkDecorator(Coffee wrapped) { super(wrapped); }
public double cost() { return wrapped.cost() + 0.5; }
}Interview Tip: A concise interview answer is:
"I make the decorator implement the same interface as the object it wraps, store a reference to the wrapped object, and add behavior before or after delegating the call. Because a decorator is itself a Component, I can stack several of them to combine behaviors, which is exactly how Java's InputStream wrappers work."