1. Introduction
Structural design patterns are about how classes and objects are put together into larger structures. The Decorator Pattern is one of them. It adds new behavior to an object while the program runs. Inheritance cannot do this, because it is fixed when the code is written.
2. The Decorator Pattern
The Decorator Pattern adds behavior to one object at runtime. Other objects of the same class are not changed. It "wraps" the object inside a decorator object. The decorator adds the new behavior and has the same interface (the same methods) as the object it wraps, so callers use it the same way.
Real-Life Analogy: The Coffee Shop
Think of ordering a coffee:
- You start with a Simple Coffee.
- You can add Milk, Sugar, or Whipped Cream.
- You do not need a new "CoffeeWithMilkAndSugar" class. You "wrap" the base coffee with the additions you want.
3. Class Diagram
In the diagram, PizzaDecorator sits in the middle. It is a Pizza and it also holds a Pizza. This lets a topping such as ExtraCheese wrap a MargheritaPizza, a PlainPizza, or another topping.
4. Problem & Solution Summary
The Problem: Class Explosion
Say you use inheritance for every mix of toppings. You get far too many classes (CheesePizza, OlivePizza, CheeseAndOlivePizza, and so on). This is called Class Explosion.
The Solution: Composition over Inheritance
The Decorator Pattern uses layers instead. Each decorator is like gift wrap around the pizza. At runtime you can stack as many layers as you like. Each layer adds its own description and cost.
5. Pros and Cons
| Pros | Cons |
|---|---|
| Open/Closed Principle: You can add new toppings (decorators) without editing existing pizza classes. | Many Small Classes: Each new feature needs its own decorator class, which can fill up the project. |
| Runtime Flexibility: Behaviors can be added dynamically while the app is running. | Complex Debugging: With many layers, stack traces (the list of calls shown in an error) are harder to follow. |
| Avoids Subclass Explosion: No need for $2^N$ classes to cover every combination. | Learning Curve: You must understand the "chaining": each decorator calls the one inside it. |
6. Real-World Use Cases
- Food Delivery Apps (Swiggy/Zomato): Dynamically adding toppings, sauces, or sides to a base food item.
- Word Processors (Google Docs): Applying text styles like Bold, Italic, or Underline in any combination.
- Java I/O Streams: Using
BufferedReader(new FileReader("file.txt"))is a classic implementation of the Decorator Pattern in the Java standard library.
Key Takeaway: The Call Stack Analogy
The Decorator Pattern works like a Call Stack. Call getCost() on the outermost decorator. It calls getCost() on the one inside it, and so on, until the base pizza answers. The values then come back up, and each layer adds its own cost.