In Decorator design pattern we have an ItemClass (p.e. Coffee), then an AbstractDecorator (p.e. CoffeeDecorator) that contains a reference to Coffee, and ConcreteDecorators (such as milk). My question is, why do we need AbstractDecorator class, why don't Concrete Decorators inherit directly from Coffee class? Or why don't we have an interface that contains ItemClass property, if we already want to ensure that ConcreteDecorators have a reference to ItemClass? Bu using this AbstractDecorator we are just disabling an option that our ConcreteDecorators inherit some other class. Thanks, in advance!
This type of design pattern comes under structural pattern as this pattern acts as a wrapper to existing class. This pattern creates a decorator class which wraps the original class and provides additional functionality keeping class methods signature intact.
The decorator pattern can be used to extend (decorate) the functionality of a certain object statically, or in some cases at run-time, independently of other instances of the same class, provided some groundwork is done at design time. This is achieved by designing a new Decorator class that wraps the original class.
Advantage of Decorator PatternIt enhances the extensibility of the object, because changes are made by coding new classes. It simplifies the coding by allowing you to develop a series of functionality from targeted classes instead of coding all of the behavior into the object.
Decorator design pattern is used to modify the functionality of an object at runtime. At the same time other instances of the same class will not be affected by this, so individual object gets the modified behavior.
We use abstract classes to remove duplication from concrete classes. In decorator pattern you have duplication of storing decorated object instance and passing calls to it. If you will not move this logic to base (abstract) decorator, then you will need to implement this in every concrete decorator.
Consider following beverage interface:
public interface IBeverage
{
decimal Price { get; }
string Description { get; }
}
which is implemented by coffee:
public class Coffee : IBeverage
{
public decimal Price
{
get { return 3.5M; }
}
public string Description
{
get { return "Coffee"; }
}
}
Now you want to create first decorator for coffee. You don't need to create abstract decorator at this moment. Let our milk bee free of charge. Just write simplest code you will 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 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 duplicated code. So, it's time to refactoring. Let's move duplicated code to base abstract decorator class, which responsibility will be holding reference to decorated beverage and passing calls to 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 override only those calls which behavior changed by your decorator. Milk decorator will look like:
public class Milk : BeverageDecorator
{
public Milk(IBeverage beverage)
: base(beverage)
{
}
public override string Description
{
get
{
return base.Description + " with milk";
}
}
}
Much cleaner, yes? That's why we use base decorator.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With