Here are a few more concrete examples of the Decorator Pattern applied in C#:
Imagine a coffee ordering system where you can customize a basic coffee with various extras like milk, sugar, and flavors using the Decorator Pattern:
using System;
// Component Interface
public interface ICoffee
{
string GetDescription();
double GetCost();
}
// Concrete Component
public class SimpleCoffee : ICoffee
{
public string GetDescription()
{
return "Simple Coffee";
}
public double GetCost()
{
return 1.0;
}
}
// Decorator
public abstract class CoffeeDecorator : ICoffee
{
protected ICoffee _coffee;
public CoffeeDecorator(ICoffee coffee)
{
_coffee = coffee;
}
public virtual string GetDescription()
{
return _coffee.GetDescription();
}
public virtual double GetCost()
{
return _coffee.GetCost();
}
}
// Concrete Decorators
public class MilkDecorator : CoffeeDecorator
{
public MilkDecorator(ICoffee coffee) : base(coffee) { }
public override string GetDescription()
{
return base.GetDescription() + ", Milk";
}
public override double GetCost()
{
return base.GetCost() + 0.5;
}
}
public class SugarDecorator : CoffeeDecorator
{
public SugarDecorator(ICoffee coffee) : base(coffee) { }
public override string GetDescription()
{
return base.GetDescription() + ", Sugar";
}
public override double GetCost()
{
return base.GetCost() + 0.2;
}
}
// Client Code
public class Program
{
public static void Main(string[] args)
{
// Create a simple coffee
ICoffee simpleCoffee = new SimpleCoffee();
Console.WriteLine($"Cost: {simpleCoffee.GetCost()}, Ingredients: {simpleCoffee.GetDescription()}");
// Decorate with milk
ICoffee milkCoffee = new MilkDecorator(simpleCoffee);
Console.WriteLine($"Cost: {milkCoffee.GetCost()}, Ingredients: {milkCoffee.GetDescription()}");
// Decorate with sugar
ICoffee milkSugarCoffee = new SugarDecorator(milkCoffee);
Console.WriteLine($"Cost: {milkSugarCoffee.GetCost()}, Ingredients: {milkSugarCoffee.GetDescription()}");
}
}