Decorator pattern dynamically attaches responsibility to the object. To expand functionality, decorators provide a more flexible alternative than inheritance.
1. Role
- Component role: The original object to be packaged is an abstract class or interface.
- The role of ConcreteComponent: The actual object to be decorated in the end is the implementation class of Component.
- Decorator role: It is an abstract class, inherited from Component, and at the same time holds a reference to the Component instance object.
- The role of ConcreteComponent: The concrete decorator object is the implementation class of Decorator and is responsible for attaching responsibilities to ConcreteComponent.
2. Demo background
- A milk tea shop can add some auxiliary materials such as oatmeal, pudding, red beans, Pearls and so on. Adding accessories may have different prices, or we need all of them, and adding multiple accessories at the same time, so that we encounter difficulties when designing objects, do we have to arrange and combine to create sub-categories? This is obviously not good, the number of classes has exploded, and the design is rigid. At this time, we can refer to the decorator pattern and replace inheritance with composition.
3. Code implementation
- Abstract component class (Component): MilkyTea
public abstract class MilkyTea (Milk tea)
{
public string description;
public abstract double GetFee();
//Unlike java, java parent class method does not need to add key The word Virtual can be rewritten in subclasses
public virtual string GetDescription()
{
return description;
}
}
- < li>ConcreteComponent: MilkGreenTea (Milk Green)
public class MilkGreenTea: MilkyTea
{
public MilkGreenTea()
{
description = "Milk Green Tea";
}
public override double GetFee()
{
return 10;
}
}
- Decorator: CondimentDecorator (accessories)
public abstract class CondimentDecorator: MilkyTea
{
public MilkyTea milkyTea;
}
- ConcreteComponent: Oats, Pudding (cloth D)
public class Oats: CondimentDecorator
{
public Oats(MilkyTea milkyTea)
{
this.milkyTea = milkyTea;
}
public override double GetFee()
{
return 1 + milkyTea.GetFee();
}
public override string GetDescription()
{
return milkyTea.GetDescription() + ",Oats";
}
}
public class Pudding: CondimentDecorator
{
public Pudding(MilkyTea milkyTea )
{
this.milkyTea = milkyTea;
}
public override double GetFee()
{
return 3 + milkyTea.GetFee();< br /> }
public override string GetDescription()
{
return milkyTea.GetDescription() + ",Pudding";
}
}
< ul>
static void Main(string[] args) {
MilkyTea tea = new MilkGreenTea();
Console.WriteLine($"{tea.GetDescription()}:¥{tea.GetFee()}. ");
tea = new Pudding(tea);
Console.WriteLine($"{((Pudding)tea).GetDescription()}:¥{tea.GetFee()}.");
tea = new Oats(tea);
Console.WriteLine($"{tea.GetDescription()}:¥{tea.GetFee()}.");
}
4. Advantages and disadvantages
- Advantages: Inject flexibility into the design. It meets the principle of opening and closing, which is convenient for expansion.
- Actually: A large number of small categories will be added to the design.
5. Source address
https://github.com/DonyGu/DesignPatterns