英文叫Decorator Pattern,又叫装饰者模式。装饰模式是在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象。
在软件开发中,我们经常想要对一类对象添加不同的功能,例如要给手机添加贴膜,手机挂件,手机外壳等,如果此时利用继承来实现的话,就需要定义无数的类,如StickerPhone(贴膜是手机类)、AccessoriesPhone(挂件手机类)等,这样就会导致 ”子类爆炸“问题,为了解决这个问题,我们可以使用装饰者模式来动态地给一个对象添加额外的职责。下面让我们看看装饰者模式。
2.1 定义
装饰者模式以对客户透明的方式动态地给一个对象附加上更多的责任,装饰者模式相比生成子类可以更灵活地增加功能。
2.2 装饰者模式实现
这里以手机和手机配件的例子来演示装饰者模式的实现,具体代码如下:
////// 手机抽象类,即装饰者模式中的抽象组件类 /// public abstract class Phone { public abstract void Print(); } ////// 苹果手机,即装饰着模式中的具体组件类 /// public class ApplePhone:Phone { ////// 重写基类方法 /// public override void Print() { Console.WriteLine("开始执行具体的对象——苹果手机"); } } ////// 装饰抽象类,要让装饰完全取代抽象组件,所以必须继承自Photo /// public abstract class Decorator:Phone { private Phone phone; public Decorator(Phone p) { this.phone = p; } public override void Print() { if (phone != null) { phone.Print(); } } } ////// 贴膜,即具体装饰者 /// public class Sticker : Decorator { public Sticker(Phone p) : base(p) { } public override void Print() { base.Print(); // 添加新的行为 AddSticker(); } ////// 新的行为方法 /// public void AddSticker() { Console.WriteLine("现在苹果手机有贴膜了"); } } ////// 手机挂件 /// public class Accessories : Decorator { public Accessories(Phone p) : base(p) { } public override void Print() { base.Print(); // 添加新的行为 AddAccessories(); } ////// 新的行为方法 /// public void AddAccessories() { Console.WriteLine("现在苹果手机有漂亮的挂件了"); } } class Customer { static void Main(string[] args) { // 我买了个苹果手机 Phone phone = new ApplePhone(); // 现在想贴膜了 Decorator applePhoneWithSticker = new Sticker(phone); // 扩展贴膜行为 applePhoneWithSticker.Print(); Console.WriteLine("----------------------\n"); // 现在我想有挂件了 Decorator applePhoneWithAccessories = new Accessories(phone); // 扩展手机挂件行为 applePhoneWithAccessories.Print(); Console.WriteLine("----------------------\n"); // 现在我同时有贴膜和手机挂件了 Sticker sticker = new Sticker(phone); Accessories applePhoneWithAccessoriesAndSticker = new Accessories(sticker); applePhoneWithAccessoriesAndSticker.Print(); Console.ReadLine(); }
从上面的客户端代码可以看出,客户端可以动态地将手机配件增加到手机上,如果需要添加手机外壳时,此时只需要添加一个继承Decorator的手机外壳类,从而,装饰者模式扩展性也非常好。
2.3 装饰者模式的类图
实现完了装饰者模式之后,让我们看看装饰者模式实现中类之间的关系,具体见下图:
在装饰者模式中各个角色有:
看完装饰者模式的详细介绍之后,我们继续分析下它的优缺点。
优点:
缺点:
下面让我们看看装饰者模式具体在哪些情况下使用,在以下情况下应当使用装饰者模式:
在.NET 类库中也有装饰者模式的实现,该类就是System.IO.Stream,下面看看Stream类结构:
上图中,BufferedStream、CryptoStream和GZipStream其实就是两个具体装饰类,这里的装饰者模式省略了抽象装饰角色(Decorator)。
到这里,装饰者模式的介绍就结束了,装饰者模式采用对象组合而非继承的方式实现了再运行时动态地扩展对象功能的能力,装饰模式是在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象。