本笔记摘抄自:https://www.cnblogs.com/PatrickLiu/p/7723225.html,记录一下学习过程以备后续查用。
一、引言
今天我们要讲结构型设计模式的第三个模式--装饰模式。当第一次看到这个名称时想到的是另外一个词语“装修”,个人观点谈谈对“装修”的理解吧,请大家看清楚现在说是“装修”而不是“装饰”。当我们长大了就要准备结婚(男大当婚女大当嫁嘛),而结婚往往涉及到要买房的事。如果买的是毛坯房,假如想要房子的内饰是大理石风格的,我们只需在毛坯房的基础之上用大理石风格的材料装修就可以(不需要重新盖房)。房子装修好了住了进来很开心,过了段时间,发现房子在冬季比较冷,于是就想给房子增加保暖的功能,此时我们只需在房子里面增加采暖系统(南方人使用变频空调)。又过了一段时间,总是有陌生人光顾,于是想给房子增加安防设备,此时我们可以在门口及室内加装监控摄像头(或者加红外、门磁等布控)及安装防盗网。随着时间的流逝,我们可能会根据我们的需求增加相应的功能,而在此期间,我们的房子都是可以正常使用的,从这一方面来讲,“装修”和“装饰”有类似的概念。下面让我们看看装饰模式具体是什么吧?
二、装饰模式介绍
装饰模式:英文名称--Decorator Pattern;分类--结构型。
2.1、动机(Motivate)
在房子装修的过程中,各种功能可以相互组合,来增加房子的功用。类似的,如果我们在软件系统中,要给某个类型或者对象增加功能,如果使用“继承”的方案来写代码,就会出现子类暴涨的情况。比如:IMarbleStyle是大理石风格的接口定义、IKeepWarm是保暖的接口定义、IHouseSecurity是房子安全的接口定义,就三个接口来说,House是我们房子,房子要什么功能就实现什么接口。如果房子要的是复合功能,接口的不同组合就会有不同的结果,但是会导致子类膨胀严重,随着功能的不断增加,会导致子类指数增长。这个问题的根源在于我们“过度地使用了继承来扩展对象的功能”,由于继承为类型引入静态特质(所谓静态特质,就是如果想要某种功能,我们必须在编译时就要定义这个类,这也是强类型语言的特点。静态,就是指在编译的时候要确定的东西;动态,是指运行时确定的东西),使得这种扩展方式缺乏灵活性,并且随着子类的增多(扩展功能的增多)及子类的组合(扩展功能的组合),会导致更多子类的膨胀(多继承)。
如何使“对象功能的扩展”能够根据需要来动态(即运行时)地实现?同时避免“扩展功能的增多”带来的子类膨胀问题?从而使得任何“功能扩展变化”所导致的影响降为最低?
2.2、意图(Intent)
动态地给一个对象增加一些额外的职责。就增加功能而言,Decorator模式比生成子类更为灵活。—— 《设计模式》GoF
2.3、结构图(Structure)
2.4、模式的组成
在装饰模式中的各个角色有:
1)抽象构件角色(Component):给出一个抽象接口,以规范准备接收附加责任的对象。
2)具体构件角色(Concrete Component):定义一个将要接收附加责任的类。
3)装饰角色(Decorator):持有一个构件(Component)对象的实例,并实现一个与抽象构件接口一致的接口。
4)具体装饰角色(Concrete Decorator):负责给构件对象添加上附加的责任。
2.5 、装饰模式的具体实现
继续拿房子的例子来说吧:
class Program { /// <summary> /// 该抽象类就是房子抽象接口的定义,该类型就相当于是Component类型,需要装饰的。 /// </summary> public abstract class House { //房子的装修方法--该操作相当于Component类型的Operation方法。 public abstract void Renovation(); } /// <summary> /// 该抽象类就是装饰接口的定义,该类型就相当于是Decorator类型,如果需要具体的功能,可以子类化该类型。 /// </summary> public abstract class DecorationStrategy : House //关键点之二,体现关系为Is-A,有这个关系,装饰的类也可以继续装饰了。 { //通过组合方式引用Decorator类型,该类型实施具体功能的增加。 //这是关键点之一,包含关系,体现为Has-A。 protected House _house; //通过构造器注入,初始化平台实现。 protected DecorationStrategy(House house) { _house = house; } //该方法就相当于Decorator类型的Operation方法。 public override void Renovation() { if (_house != null) { _house.Renovation(); } } } /// <summary> /// 我的房子,相当于ConcreteComponent类型。 /// </summary> public sealed class MyHouse : House { public override void Renovation() { Console.WriteLine("装修我的房子,比如大理石风格。"); } } /// <summary> /// 增加保暖功能,相当于ConcreteDecoratorA类型。 /// </summary> public sealed class KeepWarmDecorator : DecorationStrategy { public KeepWarmDecorator(House house) : base(house) { } public override void Renovation() { //base.Renovation(); Console.WriteLine("增加保暖功能。"); } } /// <summary> /// 增加安防设备,相当于ConcreteDecoratorB类型。 /// </summary> public sealed class SecurityDecorator : DecorationStrategy { public SecurityDecorator(House house) : base(house) { } public override void Renovation() { //base.Renovation(); Console.WriteLine("增加安防设备。"); } } static void Main(string[] args) { #region 装饰模式 //需要装饰的房子 House myHouse = new MyHouse(); myHouse.Renovation(); //增加保暖功能 DecorationStrategy warmHouse = new KeepWarmDecorator(myHouse); warmHouse.Renovation(); //如果房子既要保暖又要安防,继续装饰就行。 DecorationStrategy warmAndSecurityHouse = new SecurityDecorator(warmHouse); warmAndSecurityHouse.Renovation(); Console.Read(); #endregion } }