Decorator Design Pattern in .NET

The Decorator pattern allows you to add new behavior to objects dynamically without modifying their structure. It wraps an object to enhance or alter its behavior at runtime.

 

Purpose

To extend the functionality of objects in a flexible and reusable way without changing the original class code.

 

Key Characteristics

  • Uses composition, not inheritance
  • Decorators implement the same interface as the target object
  • Can be stacked or chained to combine behaviors

 

Pros

  • Adds behavior without modifying existing classes
  • Supports open/closed principle
  • Allows dynamic behavior composition

 

Cons

  • Many small classes can increase complexity
  • Can be harder to trace behavior flow when deeply nested

 

Use Cases

  • Adding features like logging, security, or validation to financial operations
  • Applying transaction fees, taxes, or discounts dynamically
  • Decorating notifications with audit trails or message formatting

 

Real-Time Finance Example: Adding Tax and Discount to a Payment

Let’s say you want to process a base payment and dynamically add tax and/or discount without modifying the core payment class.

 

1. Define the Component Interface

public interface IPayment

{

    decimal GetAmount();

}

 

2. Create the Concrete Component

public class BasePayment : IPayment

{

    private readonly decimal _amount;

 

    public BasePayment(decimal amount)

    {

        _amount = amount;

    }

 

    public decimal GetAmount() => _amount;

}

 

3. Create the Base Decorator

public abstract class PaymentDecorator : IPayment

{

    protected readonly IPayment _payment;

 

    protected PaymentDecorator(IPayment payment)

    {

        _payment = payment;

    }

 

    public abstract decimal GetAmount();

}

 

4. Create Concrete Decorators

public class TaxDecorator : PaymentDecorator

{

    public TaxDecorator(IPayment payment) : base(payment) { }

 

    public override decimal GetAmount()

    {

        decimal baseAmount = _payment.GetAmount();

        decimal tax = baseAmount * 0.18m; // 18% GST

        return baseAmount + tax;

    }

}

 

public class DiscountDecorator : PaymentDecorator

{

    public DiscountDecorator(IPayment payment) : base(payment) { }

 

    public override decimal GetAmount()

    {

        decimal baseAmount = _payment.GetAmount();

        decimal discount = baseAmount * 0.10m; // 10% discount

        return baseAmount - discount;

    }

}

 

5. Client Code Usage

class Program

{

    static void Main()

    {

        IPayment payment = new BasePayment(1000); // Base amount: ₹1000

 

        // Add 18% tax

        payment = new TaxDecorator(payment);

 

        // Then apply 10% discount on total (after tax)

        payment = new DiscountDecorator(payment);

 

        Console.WriteLine($"Final Amount Payable: ₹{payment.GetAmount():0.00}");

    }

}

 

Output

Final Amount Payable: ₹1062.00

 

Summary

  • Decorator Pattern lets you add features dynamically, useful for things like taxes, fees, validation, or logging
  • In finance systems, this is ideal for calculating charges, offers, or enhancements without modifying core logic
  • Promotes cleaner and modular code

Comments

Popular posts from this blog

Multiline to singleline IN C# - CODING

EF Core interview questions for beginners

EF Core interview questions for experienced