The Decorator pattern is a structural design pattern that enables dynamic addition of responsibilities to an object without altering its underlying structure. It achieves this by wrapping the object with one or more decorator classes that conform to the same interface.
Core Intent
“Attach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to subclassing for extending functionality.”
This pattern promotes flexibility and adherence to the Open-Closed Principle by allowing behavior extension through composition rather than inheritance.
When to Use Decorator
| Scenario | Use Case |
|---|---|
| Runtime behavior augmentation | Add features conditionally (e.g., discounts, wrappers) |
| Avoid subclass proliferation | Multiple combinations → exponential classes |
| Maintain single responsibility | Each decorator adds one concern |
| Transparent extension | Client unaware of decoration layers |
| Legacy code enhancement | Wrap without modification |
Avoid when:
- Overhead from multiple wrappers impacts performance
- Static extensions suffice → Use inheritance
Where It Is Used in Real Systems
| Domain | Example |
|---|---|
| UI Components | Scrollable + Bordered + Resizable Window |
| Stream I/O | Buffered + Encrypted + Compressed FileStream |
| E-Commerce | Product with optional add-ons (discount, gift wrap) |
| Logging | Console + File + Database Logger |
| Graphics | Shape with patterns, colors, textures |
Key Benefits
- Composability: Stack decorators in any order
- Single Responsibility: Each decorator focuses on one addition
- Open/Closed Principle: Extend without modifying core classes
- Transparency: Decorated objects mimic originals
- Runtime flexibility: Apply/remove dynamically
Real-World Example: E-Commerce Product Pricing with Add-Ons
An e-commerce platform allows dynamic product customization:
- Base Product (e.g., Laptop at ₹50,000)
- Decorators: 10% Discount, Gift Wrapping (+₹500), Insurance (+5% of base)
Decorators stack to compute final price (e.g., Discounted + Wrapped Laptop = ₹44,550), enabling flexible pricing without subclassing every combination.
C# Implementation
using System;
// ==================== COMPONENT ====================
public interface IProduct
{
string Description { get; }
decimal CalculatePrice();
}
// ==================== CONCRETE COMPONENT ====================
public class BasicProduct : IProduct
{
public string Name { get; }
private readonly decimal _basePrice;
public BasicProduct(string name, decimal basePrice)
{
Name = name;
_basePrice = basePrice;
}
public string Description => Name;
public decimal CalculatePrice() => _basePrice;
}
// ==================== DECORATOR BASE ====================
public abstract class ProductDecorator : IProduct
{
protected readonly IProduct _product;
protected ProductDecorator(IProduct product)
{
_product = product ?? throw new ArgumentNullException(nameof(product));
}
public virtual string Description => _product.Description;
public abstract decimal CalculatePrice();
}
// ==================== CONCRETE DECORATORS ====================
public class DiscountDecorator : ProductDecorator
{
private readonly decimal _discountPercentage;
public DiscountDecorator(IProduct product, decimal discountPercentage) : base(product)
{
_discountPercentage = discountPercentage / 100m;
}
public override string Description => $"{_product.Description} (Discounted {(_discountPercentage * 100):F0}%)";
public override decimal CalculatePrice() => _product.CalculatePrice() * (1 - _discountPercentage);
}
public class GiftWrapDecorator : ProductDecorator
{
private readonly decimal _wrapFee;
public GiftWrapDecorator(IProduct product, decimal wrapFee) : base(product)
{
_wrapFee = wrapFee;
}
public override string Description => $"{_product.Description} + Gift Wrapped";
public override decimal CalculatePrice() => _product.CalculatePrice() + _wrapFee;
}
public class InsuranceDecorator : ProductDecorator
{
public InsuranceDecorator(IProduct product) : base(product) { }
public override string Description => $"{_product.Description} + Insurance";
public override decimal CalculatePrice() => _product.CalculatePrice() + (_product.CalculatePrice() * 0.05m);
}
// ==================== CLIENT ====================
public class ShoppingCart
{
public void DisplayItem(IProduct product)
{
Console.WriteLine($"{product.Description}: ₹{product.CalculatePrice():F2}");
}
}
// ==================== DEMO ====================
class Program
{
static void Main()
{
var cart = new ShoppingCart();
// Base product
var laptop = new BasicProduct("Laptop", 50000m);
cart.DisplayItem(laptop);
// Decorate dynamically
var discountedLaptop = new DiscountDecorator(laptop, 10m);
var wrappedDiscountedLaptop = new GiftWrapDecorator(discountedLaptop, 500m);
var insuredWrappedLaptop = new InsuranceDecorator(wrappedDiscountedLaptop);
Console.WriteLine("\n=== DECORATOR PATTERN IN E-COMMERCE ===\n");
cart.DisplayItem(insuredWrappedLaptop);
// Different combination
var phone = new BasicProduct("Smartphone", 20000m);
var insuredPhone = new InsuranceDecorator(new GiftWrapDecorator(phone, 300m));
cart.DisplayItem(insuredPhone);
}
}Sample Output
Laptop: ₹50000.00
=== DECORATOR PATTERN IN E-COMMERCE ===
Laptop (Discounted 10%) + Gift Wrapped + Insurance: ₹55550.00
Smartphone + Gift Wrapped + Insurance: ₹21100.00UML Class Diagram

Participants in the Decorator Pattern
The classes and objects participating in this pattern include:
- Component (IProduct)
- Defines the interface for objects that can be decorated.
- ConcreteComponent (BasicProduct)
- The base object receiving additional behaviors.
- Decorator (ProductDecorator)
- Implements the Component interface.
- Holds a reference to a Component and delegates calls.
- ConcreteDecorator (DiscountDecorator, GiftWrapDecorator, InsuranceDecorator)
- Adds specific behaviors (e.g., modifies price).
- Wraps the component and extends functionality.
- Client
- Composes decorators around the component dynamically.
Summary Table
| Participant | Role in E-Commerce Example |
|---|---|
| Component | IProduct – pricing interface |
| ConcreteComponent | BasicProduct – base item |
| Decorator | ProductDecorator – base wrapper |
| ConcreteDecorator | DiscountDecorator, GiftWrapDecorator, InsuranceDecorator |
| Client | ShoppingCart – displays final priced item |
Advantages in E-Commerce
| Benefit | Impact |
|---|---|
| Flexible pricing | Stack discounts, add-ons dynamically |
| No explosion | Avoid subclasses for every combo |
| Modular | Reuse decorators across products |
| Runtime | Apply based on user selection |
Decorator vs Composite
| Aspect | Decorator | Composite |
|---|---|---|
| Structure | Linear chain (wrapper) | Tree hierarchy (part-whole) |
| Purpose | Add behaviors | Group objects |
| Children | Single wrapped object | Multiple children |
| Example | Product + Discount + Wrap | Category + Products |
Conclusion
The Decorator pattern is highly suitable for e-commerce when extending product functionality (e.g., pricing add-ons) dynamically. It ensures modularity and scalability, allowing seamless feature stacking without rigid inheritance hierarchies.
Widely applied in .NET Streams (BufferedStream), Java I/O, and e-commerce engines like WooCommerce for modular extensions.




