Decorator Pattern: Definition, Example, and Use Cases
decorator pattern is a design pattern that lets you add new features to an object dynamically without changing its structure. It wraps the original object with a new object that adds the extra behavior, keeping the original object intact.How It Works
Imagine you have a plain coffee, but you want to add milk or sugar without changing the coffee itself. The decorator pattern works like adding layers of toppings on your coffee cup. Each topping (decorator) adds something new, but the coffee (original object) stays the same.
Technically, the decorator pattern wraps an object inside another object that has the same interface. This wrapper object adds new behavior before or after delegating calls to the original object. You can stack many decorators to combine features flexibly.
Example
This example shows a simple text message that can be decorated with uppercase and exclamation mark decorators.
from abc import ABC, abstractmethod class Message(ABC): @abstractmethod def get_text(self) -> str: pass class SimpleMessage(Message): def __init__(self, text: str): self._text = text def get_text(self) -> str: return self._text class MessageDecorator(Message): def __init__(self, message: Message): self._message = message def get_text(self) -> str: return self._message.get_text() class UppercaseDecorator(MessageDecorator): def get_text(self) -> str: return self._message.get_text().upper() class ExclamationDecorator(MessageDecorator): def get_text(self) -> str: return self._message.get_text() + "!" # Usage simple = SimpleMessage("hello world") upper = UppercaseDecorator(simple) excited = ExclamationDecorator(upper) print(excited.get_text())
When to Use
Use the decorator pattern when you want to add responsibilities to objects at runtime without altering their code. It is helpful when subclassing would create too many classes or when you want to combine features flexibly.
Real-world examples include adding scrollbars or borders to UI elements, adding encryption or compression to data streams, or extending logging behavior dynamically.
Key Points
- Decorator wraps an object to add new behavior.
- It keeps the original object's interface unchanged.
- Multiple decorators can be combined flexibly.
- It avoids subclass explosion by using composition.