Brewing Code Elegance with the Decorator Pattern
Welcome, fellow coders! Today, let's embark on a journey through the aromatic realms of design patterns, with a particular focus on the Decorator Pattern with the help of C#. If you've ever found yourself yearning for a flexible and elegant way to enhance the functionality of your classes, the Decorator Pattern might just be the secret ingredient you've been searching for.
Components of Decorator Pattern (Ingredients)
In our quest for code elegance, we begin with the essential components of the Decorator Pattern:
Component Interface (ICoffee)
public interface ICoffee
{
int Cost();
}
This is the blueprint, defining the core functionality that both concrete components and decorators will adhere to. In our scenario, it's the `ICoffee` interface with a `Cost` method.
Concrete Component (SimpleCoffee)
public class SimpleCoffee : ICoffee
{
public int Cost()
{
return 10;
}
}
Our journey starts with a simple coffee implementation, adhering to the `ICoffee` interface and providing a base cost.
Decorator (CoffeeDecorator):
public abstract class CoffeeDecorator : ICoffee
{
protected ICoffee _coffee;
public CoffeeDecorator(ICoffee coffee)
{
_coffee = coffee;
}
public virtual int Cost()
{
return _coffee.Cost();
}
}
The decorator, an abstract class, wraps around the components. It extends the `ICoffee` interface and holds a reference to a `Coffee` object, allowing it to modify or extend its behaviour.
Concrete Decorators (MilkDecorator, SugarDecorator)
public class MilkDecorator : CoffeeDecorator
{
public MilkDecorator(ICoffee coffee) : base(coffee) { }
public override int Cost()
{
return _coffee.Cost() + 5;
}
}
public class SugarDecorator : CoffeeDecorator
{
public SugarDecorator(ICoffee coffee) : base(coffee) { }
public override int Cost()
{
return _coffee.Cost() + 2;
}
}
Concrete decorators extend the abstract decorator, introducing specific modifications to the base component's behaviour.
Brewing Code Magic
Now, let's see this pattern in action:
ICoffee coffee = new SimpleCoffee();
Console.WriteLine("Cost of Simple Coffee: " + coffee.Cost());
ICoffee milkCoffee = new MilkDecorator(coffee);
Console.WriteLine("Cost of Coffee with Milk: " + milkCoffee.Cost());
ICoffee sugarMilkCoffee = new SugarDecorator(milkCoffee);
Console.WriteLine("Cost of Coffee with Milk and Sugar: " + sugarMilkCoffee.Cost());
Here, we create a simple coffee, decorate it with milk, and further enhance it with sugar. Each decorator seamlessly adds its unique flavour to the base component, showcasing the power and flexibility of the Decorator Pattern.
Conclusion: Sip, Sip, Hooray for Code Elegance!
As we conclude our exploration of the Decorator Pattern, let's raise our virtual coffee mugs to the beauty of elegant code design. With decorators gracefully wrapping and extending the behaviour of our components, we've learned how to achieve flexibility without sacrificing simplicity.
So, whether you're crafting software solutions or your favourite cup of coffee, remember the Decorator Pattern – a delightful recipe for code elegance.
🤗
Good
Nicely written