牢记:代码应该如同晚霞中的莲花一样地关闭(免于改变),如同晨曦中的莲花一样地开放(能够扩展)。
3.1装饰者模式定义:
动态地将动作附加到对象上,动作可以根据需要任意叠加(装饰)。若要扩展功能,装饰者提供了比继承更有弹性的替代方案。
3.2装饰者模式UML类图:
Component是被装饰者和装饰者之间所共同拥有的行为,可以抽象类或接口的方式实现,有别于以传统的以抽象类实现的方式,本文中以接口的方式来实现。Decorator为装饰者共同拥有的行为,同样以接口的方式实现。
3.3应用场景
装饰在生活中的理解,即是某种东西被几种不同的东西来修饰。例如生日蛋糕上可能有蜡烛,也可能有文字,也可能有水果,蜡烛、文字、水果都是用来装饰蛋糕的。当我们计算蛋糕的价格时,所有的装饰者和蛋糕(被装饰者)都有一个共同的动作,即各自计算自己的价格,然后全部相加,即得出整个蛋糕的价格。实际上,当一个对象和N个其它对象之间都有共同的动作(接口相同),而且有需求将这N个对象(装饰者)任意的动态的将动作叠加在一个对象(被装饰者)上,那么,我们就可以利用装饰者模式。
3.4装饰者模式分析与实现(c#描述)
//装饰者和被装饰者共同实现的接口
public interface IBehavior
{
string GetDescription();
int Cost();
}
//装饰者实现的接口
public interface IDecorator : IBehavior
{
void ReportMyQulity();//报告装饰者的质量
}
//被装饰者:蛋糕
public class Cake : IBehavior
{
public string GetDescription()
{
return "I'm a Cake.";
}
public int Cost()
{
return 2;
}
}
//装饰者:蜡烛
public class Candle : IDecorator
{
private IBehavior iBehavior;
public Candle(IBehavior ai_Behavior)
{
this.iBehavior = ai_Behavior;
}
public string GetDescription()
{
return iBehavior.GetDescription() + " Decorated by Lazhu. ";
}
public int Cost()
{
return iBehavior.Cost() + 3;
}
public void ReportMyQulity()
{
Console.WriteLine("我质量很好的!");
}
}
//装饰者:文字
public class Text : IDecorator
{
private IBehavior iBehavior;
public Text(IBehavior ai_Behavior)
{
this.iBehavior = ai_Behavior;
}
public string GetDescription()
{
return this.iBehavior.GetDescription() + " Decorated by Text. ";
}
public int Cost()
{
return this.iBehavior.Cost() + 3;
}
public void ReportMyQulity()
{
Console.WriteLine("我质量一般!");
}
}
//装饰者:水果
public class Fruit : IDecorator
{
private IBehavior iBehavior;
public Fruit(IBehavior ai_Behavior)
{
this.iBehavior = ai_Behavior;
}
public string GetDescription()
{
return this.iBehavior.GetDescription() + " Decorated by Fruit. ";
}
public int Cost()
{
return this.iBehavior.Cost() + 5;
}
public void ReportMyQulity()
{
Console.WriteLine("我质量不好哦!");
}
}
//调用类
public class Decorator_Test
{
public static void Do()
{
IBehavior Cake = new Cake();//建一个被装饰者
Cake = new Candle(Cake);//用蜡烛来装饰
Cake = new Text(Cake);//用文字来装饰
Cake = new Fruit(Cake);//用水果来装饰
Console.WriteLine(Cake.GetDescription()+" 我的成本是:"+Cake.Cost()+"元。");
}
}
至此,装饰者模式完毕。
装饰者模式体现了上述的面向对象设计的几个原则,下面重点强调一下其中之一:类应该对扩展开放,对修改关闭。
很明显,在装饰者模式中,如果我们要扩展一个类的行为,则只需为其添加不同的装饰者,而不需要修改被装饰者的任何代码,一个蛋糕可以用水果来装饰,也可以用文字来装饰,也可以用蜡烛装饰2次,也可以完全不装饰,这些都取决于客户的实际需要。我们可以用无数个装饰者包装一个对象,但装饰者模式的缺点是:装饰者模式会导致设计中出现许多小对象,如果过度使用,会让程序变得复杂。