The Decorator Design Pattern is a structural pattern that allows you to dynamically add behavior or responsibilities to an object without modifying its structure. It is particularly useful when you need to enhance the functionality of an object at runtime in a flexible and reusable way.
Key Components of the Decorator Pattern
Component: Defines the interface or abstract class for objects that can have responsibilities added to them dynamically.
Concrete Component: The base implementation of the component interface.
Decorator: An abstract class that implements the component interface and contains a reference to a component object.
Concrete Decorators: Extend the functionality of the component by adding specific behaviors.
Real-Life Example in a Retail Application
Imagine you are building a retail application where customers can place orders. The application supports adding optional features like gift wrapping and express delivery to the order.
Using the Decorator pattern, you can dynamically add these features to an order without modifying the core order logic.
Implementation
Component Interface
Define the basic operations for an order.public interface Order { double getCost(); String getDescription(); }
Concrete Component
The base implementation of an order.public class BasicOrder implements Order { @Override public double getCost() { return 500; // Base cost of an order } @Override public String getDescription() { return "Basic Order"; } }
Decorator
Abstract class for decoratorspublic abstract class OrderDecorator implements Order { protected Order order; public OrderDecorator(Order order) { this.order = order; } @Override public double getCost() { return order.getCost(); } @Override public String getDescription() { return order.getDescription(); } }
Concrete Decorators
Add specific behaviors like gift wrapping and express delivery.public class GiftWrapping extends OrderDecorator { public GiftWrapping(Order order) { super(order); } @Override public double getCost() { return super.getCost() + 50; // Add cost for gift wrapping } @Override public String getDescription() { return super.getDescription() + ", Gift Wrapped"; } } public class ExpressDelivery extends OrderDecorator { public ExpressDelivery(Order order) { super(order); } @Override public double getCost() { return super.getCost() + 100; // Add cost for express delivery } @Override public String getDescription() { return super.getDescription() + ", Express Delivery"; } }
Usage
Combine decorators dynamically.public class RetailApp { public static void main(String[] args) { Order order = new BasicOrder(); System.out.println(order.getDescription() + " -> Cost: " + order.getCost()); // Add Gift Wrapping order = new GiftWrapping(order); System.out.println(order.getDescription() + " -> Cost: " + order.getCost()); // Add Express Delivery order = new ExpressDelivery(order); System.out.println(order.getDescription() + " -> Cost: " + order.getCost()); } }
Output
Basic Order -> Cost: 500.0 Basic Order, Gift Wrapped -> Cost: 550.0 Basic Order, Gift Wrapped, Express Delivery -> Cost: 650.0
Real-World Applications
Retail/E-commerce: Adding features like gift wrapping, priority shipping, or discounts.
Streaming Services: Adding premium features like HD streaming or offline downloads.
Gaming: Adding enhancements like skins, extra lives, or premium features to a character.