🍦 Level Up Your Java & Design Pattern Skills!
Enjoying this practical tutorial? Subscribe to Ram N Java for clean code, object-oriented best practices, and detailed programming walkthroughs.
🔔 Subscribe to Ram N JavaWhat is the Decorator Design Pattern?
The Decorator Pattern is a structural design pattern that lets you dynamically attach new behaviors, responsibilities, or properties to an object at runtime without altering its original class structure.
Instead of subclassing (inheritance), which creates an overwhelming number of classes for every feature combination, the Decorator Pattern relies on composition—wrapping objects inside other decorator objects seamlessly.
The Real-World Scenario: Building Custom Ice Creams
Imagine ordering an ice cream. You start with a base Simple Ice Cream. From there, you might want to add toppings like:
- Nuts
- Honey
- Chocolate Syrup
If you attempted to create subclasses for every single mix-and-match order (like IceCreamWithHoneyAndNuts, IceCreamWithNutsOnly, etc.), your codebase would quickly explode with dozens of redundant classes.
With the Decorator Pattern, each topping is a wrapper that decorates the base ice cream, calculates the updated cost, and adds description details dynamically!
Step-by-Step Code Walkthrough
1. Component Interface
Define the core interface that both base ice creams and decorators will share:
public interface Icecream {
String makeIcecream();
}
2. Concrete Component
Provide a base implementation representing standard, un-decorated ice cream:
public class SimpleIcecream implements Icecream {
@Override
public String makeIcecream() {
return "Base Ice Cream";
}
}
3. Abstract Decorator
The decorator implements Icecream and maintains a reference to the wrapped Icecream object:
public abstract class IcecreamDecorator implements Icecream {
protected Icecream specialIcecream;
public IcecreamDecorator(Icecream specialIcecream) {
this.specialIcecream = specialIcecream;
}
@Override
public String makeIcecream() {
return specialIcecream.makeIcecream();
}
}
4. Concrete Decorators (Toppings)
Add specific toppings by extending the decorator and chaining the behavior:
public class NuttyDecorator extends IcecreamDecorator {
public NuttyDecorator(Icecream specialIcecream) {
super(specialIcecream);
}
@Override
public String makeIcecream() {
return specialIcecream.makeIcecream() + " + Crunchy Nuts";
}
}
public class HoneyDecorator extends IcecreamDecorator {
public HoneyDecorator(Icecream specialIcecream) {
super(specialIcecream);
}
@Override
public String makeIcecream() {
return specialIcecream.makeIcecream() + " + Sweet Honey";
}
}
5. Putting It All Together
public class TestDecorator {
public static void main(String[] args) {
Icecream myOrder = new HoneyDecorator(new NuttyDecorator(new SimpleIcecream()));
System.out.println(myOrder.makeIcecream());
// Output: Base Ice Cream + Crunchy Nuts + Sweet Honey
}
}
Why Use the Decorator Pattern?
- Open/Closed Principle: Add endless new toppings without modifying existing classes.
- Dynamic Assembly: Stack and nest toppings arbitrarily at runtime.
- Clean Architecture: Avoids monstrous class hierarchies.
Related Tutorials You Might Like
Enhance your software engineering toolkit with these related design pattern tutorials:
Click here to watch in Youtube : https://www.youtube.com/watch?v=-CSs47U8H4k
| Decorator Design pattern - Implementation [Ice Cream] - Class Diagram |
Icecream.java
No comments:
Post a Comment