Using the Abstract Decorator Class in a Decorator Template

In the design design of Decorator, we have ItemClass (pe Coffee), then AbstractDecorator (pe CoffeeDecorator), which contains a link to Coffee and ConcreteDecorators (e.g. milk). My question is, why do we need the AbstractDecorator class, why don't Concrete decorators inherit directly from the Coffee class? Or why don't we have an interface that contains the ItemClass property if we already want ConcreteDecorators to reference ItemClass? Using this AbstractDecorator, we simply disabled the option that our ConcreteDecorators inherit from some other class. Thanks in advance!

+6
source share
1 answer

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; } // price not changed } public string Description { get { return _beverage.Description + " with milk"; } } } 

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.

+1
source

Source: https://habr.com/ru/post/956228/


All Articles