装饰器模式组成:
- 抽象组件角色(Component): 定义可以动态添加任务的对象的接口
- 具体组件角色(ConcreteComponent):定义一个要被装饰器装饰的对象,即 Component 的具体实现
- 抽象装饰器(Decorator): 维护对组件对象和其子类组件的引用
- 具体装饰器角色(ConcreteDecorator):向组件添加新的职责
一.装饰者模式的定义:
装饰模式是在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象。
举一个例子:假如我们去奶茶店买奶茶,有两个品种蜂蜜奶茶和珍珠奶茶。这两种奶茶分别可以加糖,加牛奶,加冰等等 加不同的料收费不同,如果我们想要用程序输出他们的价格和名字如何做呢?首先想到的就是把他们公共的部分抽象成一个接口,不管是什么奶茶都有价格,名称于是我们可以把这一部分抽象成接口。然后用去实现这个接口,那么会有蜂蜜奶茶类,蜂蜜奶茶加糖,蜂蜜奶茶加牛奶等等的类。这还仅仅只是加一种料哦,如果可以需要加糖又加牛奶那么又需要一个类,这样设计的话我们的子类会非常的繁多。所以应对这种情景的设计模式就出现了。贴上代码
#region component构建接口(抽象构建) ,奶茶接口,提供奶茶名称以及奶茶价格方法
public interface IMilkTea
{
void MilkTeaName();
int MilkPrice();
}
#endregion
#region ConcreteComponent 具体构建(主体类)也就是需要拓展的对象
public class HoneyTea : IMilkTea
{
public int MilkPrice()
{
return 20;
}
public void MilkTeaName()
{
Console.Write("蜂蜜奶茶");
}
}
public class PeralTea : IMilkTea
{
public int MilkPrice()
{
return 15;
}
public void MilkTeaName()
{
Console.Write("珍珠奶茶");
}
}
#endregion
#region Decorator类
public class TeaDecorator : IMilkTea
{
protected IMilkTea milkTea;
public TeaDecorator(IMilkTea milkTea)
{
this.milkTea = milkTea;
}
public int MilkPrice()
{
int normalPrice = milkTea.MilkPrice();
int addPrice = this.AddPrice();
return normalPrice + addPrice;
}
public void MilkTeaName()
{
milkTea.MilkTeaName();
this.AddName();
}
public virtual void AddName()
{
}
public virtual int AddPrice()
{
return 0;
}
}
#endregion
#region ConcreteDecorator具体装饰类
public class AddCoffeeDecorator : TeaDecorator
{
public AddCoffeeDecorator(IMilkTea milkTea) : base(milkTea)
{
}
public override void AddName()
{
Console.Write("添加了咖啡");
}
public override int AddPrice()
{
return 15;
}
}
public class AddIceDecorator : TeaDecorator
{
public AddIceDecorator(IMilkTea milkTea) : base(milkTea)
{
}
public override void AddName()
{
Console.Write("添加了冰块");
}
public override int AddPrice()
{
return 5;
}
}
#endregion
TeaDecorator 装饰器类,它里面有抽象接口的引用,当运行起来的时候它实际上就是表示具体被装饰对象。该设计模式主要用来拓展对象的功能。来看看它如何被调用
//Decorator装饰模式
//需要扩展一个类的功能,或给一个类增加附加功能。
//需要动态的给一个对象增加功能时(可随时撤销)。
//例如下面一个例子:假如不止是蜂蜜奶茶和珍珠奶茶
//假如不止是加咖啡和冰块,假设6种名称的奶茶和10种口味的
//将他们设计成类的话至少有6*10个类(不包括组合的,一种奶茶加很多口味的情况)
IMilkTea honeyTea = new HoneyTea();
honeyTea.MilkTeaName();
Console.WriteLine("价格是:" + honeyTea.MilkPrice());
honeyTea = new AddCoffeeDecorator(honeyTea);
honeyTea.MilkTeaName();
Console.WriteLine("价格是:" + honeyTea.MilkPrice());
honeyTea = new AddIceDecorator(honeyTea);
honeyTea.MilkTeaName();
Console.WriteLine("价格是:" + honeyTea.MilkPrice());
输出如下: