示例代码
今天实在是想不出什么开场白来引出示例了,也想不出特别有意思的示例了,就用一个很土的例子来描述一下装饰器模式吧。
每个人都要穿衣服,每件衣服都具有某些特定的功能,例如,穿上鞋子的话走路舒服,穿上上衣的话上身不冷,穿上裤子的话腿不冷(你这不废话吗)。也就是说,每件衣服都具有特定的职责,每穿一件衣服,都会动态地给自己添加一项职责。来看实例代码
首先,定义一个衣服的接口,然后给出默认的实现
public interface IClothes
{
void GetInfo();
}
/// <summary>
/// 默认的实现,用来生成第一个对象
/// </summary>
class DefaultClothes : IClothes
{
public void GetInfo()
{
Console.WriteLine("默认的实现");
}
}
然后写一个关键的类,就是我们的装饰器类
public class ClothesDecorator:IClothes
{
private IClothes clothes;
public ClothesDecorator(IClothes clothes)
{
this.clothes = clothes;
}
public virtual void GetInfo()
{
clothes.GetInfo();
}
}
仔细一看,你这家伙好狡猾,自己的GetInfo方法不自己写,而是调用依赖对象的GetInfo方法,看起来跟代理模式有些相似哈。接着往下看,每件衣服都是一个装饰器,继承自ClothesDecorator。
public class ShoseDecorator : ClothesDecorator
{
private IClothes clothes;
public ShoseDecorator(IClothes clothes)
: base(clothes)
{
this.clothes = clothes;
}
public override void GetInfo()
{
Console.WriteLine("穿了双鞋子");
base.GetInfo();
}
}
public class CoatDecorator:ClothesDecorator
{
private IClothes clothes;
public CoatDecorator(IClothes clothes)
: base(clothes)
{
this.clothes = clothes;
}
public override void GetInfo()
{
Console.WriteLine("穿了个外套");
base.GetInfo();
}
}
public class PantsDecorator : ClothesDecorator
{
private IClothes clothes;
public PantsDecorator(IClothes clothes)
: base(clothes)
{
this.clothes = clothes;
}
public override void GetInfo()
{
Console.WriteLine("穿了条裤子");
base.GetInfo();
}
}
好,装饰器模式的代码已经写好了,看上去没有什么难懂的地方对吧。但是,客户端在调用的时候很有意思,给一个对象包装一层又一层,使这个对象的职责越来越强大。下面是使用场景
class Program
{
static void Main(string[] args)
{
IClothes clothes = new DefaultClothes();
clothes = new CoatDecorator(clothes);
clothes = new PantsDecorator(clothes);
clothes = new ShoseDecorator(clothes);
clothes.GetInfo();
}
}
神奇的输出结果:
穿了双鞋子
穿了条裤子
穿了个外套
默认的实现
在这个实例中,通过一层又一层的装饰,最初的对象具备了更多对象的职责,可以按照特定的业务需求进行装饰,原始对象和装饰器对象都实现了同一个接口,所以,不管如何包装,最后还是用一个简单的方法来调用(即clothes.GetInfo()),所有的装饰器对象具备的职责都依次执行了。
我觉得有必要对两个类进行解释:
- DefaultClothes。这个类其实没有太大的用处,但不可缺少。它提供了IClothes接口的默认实现,能够直接实例化对象而已。它是一个最初的被装饰的对象。
- ClothesDecorator。这个类是最核心的类,首先它组合了一个被装饰的对象,并且还会调用被装饰对象的指定方法。当最初的对象被装饰了N次后,ClothesDecorator就好像是一个链表的表头,而每一个被装饰对象都是链表中的一个元素,当前的装饰器执行完了以后,都会调用下一个链表元素的方法,即
base.GetInfo()
,直到所有的装饰器的方法都执行完毕为止。DefaultClothes对象是最后一个元素,因为他是最初被装饰的对象,只能被装饰,不能装饰别人。
认识装饰器模式
装饰器模式的定义:动态地给一个对象添加一些额外的职责。就增加功能来说,装饰器模式比生成子类更加灵活。
装饰器模式的特点就是,定义一系列的职责,每一个职责都是一个特定功能的装饰器类,然后,一个对象可以通过一层又一层的对象组合,动态地去扩展自己的功能。
在面向对象的设计中,有一条基本的规则是,尽量使用对象组合,而不是对象继承来扩展和复用功能。装饰器模式就是一个通过对象组合来动态地扩展对象功能的绝佳的例子。
如果你看到这里不是很明白,很正常,因为我和一般的IT男一样,只会写代码,不太会表达和沟通。所以,如果想更加深刻地理解这个设计模式或上面的示例代码,可以把代码复制到本地,编译运行一个,跟踪一下代码的执行堆栈。