We use abstract classes to remove duplication from specific classes. In the decoratorโs template, you have duplicate storage of an instance of a decorated object and transferring calls to it. If you do not move this logic to the base (abstract) decorator, then you will need to implement this in each specific decorator.
Consider the following interface for drinks:
public interface IBeverage { decimal Price { get; } string Description { get; } }
which is sold coffee:
public class Coffee : IBeverage { public decimal Price { get { return 3.5M; } } public string Description { get { return "Coffee"; } } }
Now you want to create the first coffee decorator. At the moment, you do not need to create abstract decorators. Let our milk bee be free. Just write the simplest code you need:
public class Milk : IBeverage { private readonly IBeverage _beverage; public Milk(IBeverage beverage) { _beverage = beverage; } public decimal Price { get { return _beverage.Price; }
Now you need another decorator. Let it be a cream:
public class Cream : IBeverage { private readonly IBeverage _beverage; public Cream(IBeverage beverage) { _beverage = beverage; } public decimal Price { get { return _beverage.Price + 2M; } } public string Description { get { return _beverage.Description + " with cream"; } } }
You can see the duplicated code. So, it's time to refactor. Let me move the duplicated code to the base class of the abstract decorator, whose duties will include a link to the decorated drink and passing it:
public abstract class BeverageDecorator : IBeverage { private readonly IBeverage _beverage; public BeverageDecorator(IBeverage beverage) { _beverage = beverage; } public virtual decimal Price { get { return _beverage.Price; } } public virtual string Description { get { return _beverage.Description; } } }
Now you can redefine only those calls whose behavior has changed by your decorator. The milk decorator will look like this:
public class Milk : BeverageDecorator { public Milk(IBeverage beverage) : base(beverage) { } public override string Description { get { return base.Description + " with milk"; } } }
Significantly cleaner, right? That is why we use the base decorator.