The Decorator Pattern
is a powerful structural design pattern that enables adding new behavior to objects dynamically without modifying their original code. This is especially useful when you want to extend functionalities without creating a complex hierarchy of subclasses.
In this article, I’ll explain the Decorator Pattern using a practical example: customizing a MacBook with different configurations like upgrading RAM, SSD, and adding AppleCare protection.
What is the Decorator Pattern?
The Decorator Pattern allows you to "wrap" an object with additional features or responsibilities at runtime. Instead of creating many subclasses for every possible combination, decorators let you compose behaviors dynamically by stacking objects.
The MacBook Example Overview
We start with a base MacBook configuration:
- 16GB RAM
- 256GB SSD
- Base price
- Using decorators, we can:
- Upgrade RAM to 24GB
- Upgrade SSD to 512GB
- Add AppleCare protection
Each decorator modifies the price and relevant specs accordingly.
Core Components
The Interface IMacBook
Defines the contract with methods like:
- GetDescription()
- GetPrice()
- GetRamSize()
- GetSSDSize()
The Base Class BaseMacBook16Ram256SSD
Implements IMacBook
and represents the default MacBook configuration.
The Abstract Decorator MackBookDecorator
This class implements IMacBook
and wraps another IMacBook
instance. It delegates calls to the wrapped instance but can be extended to add or override behavior.
Concrete Decorators
-
MacBookWithAppleCare
: Adds AppleCare price and description. -
MacBook512SSD
: Adds extra SSD storage and price. -
MacBook24RAM
: Adds extra RAM and price.
How to Use It
You can compose different MacBook configurations by wrapping the base object with decorators like this:
IMacBook macBook16Ram256SSD = new BaseMacBook16Ram256SSD();
IMacBook macBook16Ram512Sdd = new MacBook512SSD(macBook16Ram256SSD);
IMacBook macBook24Ram512Sdd = new MacBook24RAM(macBook16Ram512Sdd);
IMacBook macBook24Ram512SddWithAppleCare = new MacBookWithAppleCare(macBook24Ram512Sdd);
Console.WriteLine(macBook16Ram256SSD);
Console.WriteLine(macBook16Ram512Sdd);
Console.WriteLine(macBook24Ram512Sdd);
Console.WriteLine(macBook24Ram512SddWithAppleCare);
Each line creates a new configuration by decorating the previous one.
Why Use the Decorator Pattern?
- Open/Closed Principle: Extend object behavior without changing existing code.
- Flexibility: Combine decorators in any order to create new behaviors.
- Avoids Class Explosion: No need to create a subclass for every combination.
Real-World Applications
The Decorator Pattern is widely used in software development:
- Adding scrollbars or borders in UI frameworks.
- Enhancing functionalities like logging, caching, or security by wrapping services.
- Customizing product configurations dynamically, just like our MacBook example.
Conclusion
The Decorator Pattern is an elegant way to add responsibilities to objects dynamically and flexibly. Using this pattern, you keep your codebase maintainable and avoid unnecessary class proliferation.
You can find the full source code for this example on my GitHub repository: DecoratorPattern
Top comments (0)
Some comments may only be visible to logged-in visitors. Sign in to view all comments.