loader

Ever wanted to trick out your ride with all the cool extras—like a sports package or a luxury upgrade—without buying a whole new car? That’s what the Decorator Pattern does for your code. It lets you dynamically add new features to an object without altering its core, just like customizing a basic car to suit your style.

Why Bother with It?

  • Custom Upgrades on Demand: Just as you can add a fancy spoiler or premium sound system to a car, the Decorator Pattern lets you “decorate” an object with additional responsibilities as needed.
  • Flexible Enhancements: Instead of creating a ton of subclasses for every possible combination of features, you can mix and match decorators to get exactly what you want.
  • Keep the Core Intact: Your base car remains the same; you’re simply adding layers of functionality—without rewriting the blueprint every time.

How It Works (In Plain English)

  1. The Base Car: Start with a simple car (your core object) that has basic features.
  2. The Decorators: Create add-ons (decorators) that wrap around the base car to add new capabilities—like a sports package or a luxury package.
  3. Mix and Match: Wrap your car with one or more decorators to get a fully customized ride, all while keeping the original structure intact.

C# Code Example

C#
using System;

// The component interface representing a car.
public interface ICar
{
    string GetDescription();
    double GetCost();
}

// Concrete component: A basic car.
public class BasicCar : ICar
{
    public string GetDescription() => "Basic Car";
    public double GetCost() => 15000;
}

// Abstract decorator class that implements ICar.
public abstract class CarDecorator : ICar
{
    protected ICar _car;
    
    public CarDecorator(ICar car)
    {
        _car = car;
    }
    
    public virtual string GetDescription() => _car.GetDescription();
    public virtual double GetCost() => _car.GetCost();
}

// Concrete decorator: Adds a sports package.
public class SportsPackage : CarDecorator
{
    public SportsPackage(ICar car) : base(car) { }
    
    public override string GetDescription() => _car.GetDescription() + ", Sports Package";
    public override double GetCost() => _car.GetCost() + 5000;
}

// Concrete decorator: Adds a luxury package.
public class LuxuryPackage : CarDecorator
{
    public LuxuryPackage(ICar car) : base(car) { }
    
    public override string GetDescription() => _car.GetDescription() + ", Luxury Package";
    public override double GetCost() => _car.GetCost() + 8000;
}

// Client code: customizing your car.
public class Program
{
    public static void Main()
    {
        ICar car = new BasicCar();
        Console.WriteLine(car.GetDescription() + " costs $" + car.GetCost());

        // Add a sports package.
        car = new SportsPackage(car);
        Console.WriteLine(car.GetDescription() + " costs $" + car.GetCost());

        // Add a luxury package on top.
        car = new LuxuryPackage(car);
        Console.WriteLine(car.GetDescription() + " costs $" + car.GetCost());
    }
}

The Takeaway

The Decorator Pattern is like having a top-notch car customization shop. You start with a basic model and then add exactly the features you want—be it a sporty edge or a touch of luxury—without altering the original blueprint. This approach makes your code more flexible and avoids the need for a separate subclass for every combination of features.

Happy customizing, and drive your code in style!