今天咱们要讲【结构型】设计模式的第三个模式,该模式是【装饰模式】,英文名称:Decorator Pattern。我第一次看到这个名称想到的是另一个词语“装修”,我就说说我对“装修”的理解吧,你们必定要看清楚,是“装修”,不是“装饰”。咱们长大了,就要结婚,要结婚就涉及到要买房子,买的精装修或者简单装修就能够住的,暂时不谈。咱们就谈谈咱们购买的是毛坯房。若是我想要房子的内饰是大理石风格的,咱们只要在毛坯房的基础之上用大理石风格的材料装修就能够,咱们固然不可能为了要一个装修风格,就把刚刚盖好的房子拆了在从新来过。房子装修好了,咱们就住了进来,很开心。过了段时间,咱们发现咱们的房子在冬季比较冷,因而我就想给咱们的房子增长保暖的功能,装修好的房子咱们能够继续居住,咱们只是在房子外面加一层保护层就能够了。又过了一段时间,老是有陌生人光顾,因此咱们想让房子更安全,因而咱们在外墙和房顶加装安全摄像头,同时门窗也增长安全系统。随着时间的流逝,咱们可能会根据咱们的需求增长相应的功能,期间,咱们的房子能够正常使用,加上什么设施就有了相应的功能。从这一方面来说,“装修”和“装饰”有相似的概念,接下来就让咱们看看装饰模式具体是什么吧!
2、装饰模式的详细介绍
2.一、动机(Motivate)
在房子装修的过程当中,各类功能能够相互组合,来增长房子的功用。相似的,若是咱们在软件系统中,要给某个类型或者对象增长功能,若是使用“继承”的方案来写代码,就会出现子类暴涨的状况。好比:IMarbleStyle是大理石风格的一个功能,IKeepWarm是保温的一个接口定义,IHouseSecurity是房子安全的一个接口,就三个接口来讲,House是咱们房子,咱们的房子要什么功能就实现什么接口,若是房子要的是复合功能,接口不一样的组合就有不一样的结果,这样就致使咱们子类膨胀严重,若是须要在增长功能,子类会成指数增加。这个问题的根源在于咱们“过分地使用了继承来扩展对象的功能”,因为继承为类型引入的静态特质(所谓静态特质,就是说若是想要某种功能,咱们必须在编译的时候就要定义这个类,这也是强类型语言的特色。静态,就是指在编译的时候要肯定的东西;动态,是指运行时肯定的东西),使得这种扩展方式缺少灵活性;而且随着子类的增多(扩展功能的增多),各类子类的组合(扩展功能的组合)会致使更多子类的膨胀(多继承)。如何使“对象功能的扩展”可以根据须要来动态(即运行时)地实现?同时避免“扩展功能的增多”带来的子类膨胀问题?从而使得任何“功能扩展变化”所致使的影响降为最低?
2.二、意图(Intent)
动态地给一个对象增长一些额外的职责。就增长功能而言,Decorator模式比生成子类更为灵活。 —— 《设计模式》GoF
2.三、结构图(Structure)
2.四、模式的组成
在装饰模式中的各个角色有:
(1)、抽象构件角色(Component):给出一个抽象接口,以规范准备接收附加责任的对象。
(2)、具体构件角色(Concrete Component):定义一个将要接收附加责任的类。
(3)、装饰角色(Decorator):持有一个构件(Component)对象的实例,并实现一个与抽象构件接口一致的接口。
(4)、具体装饰角色(Concrete Decorator):负责给构件对象添加上附加的责任。
2.5 、装饰模式的具体代码实现
刚开始一看这个“装饰模式”是有点不太好理解,既然这个模式是面向对象的设计模式,那在现实生活中必定有事例和其对应,其实这种例子也很多,你们好好的挖掘吧,也能够提升咱们对面向对象的理解。我继续拿盖房子来讲事吧。
javascript
1 namespace 装饰模式的实现 2 { 3 /// <summary> 4 /// 该抽象类就是房子抽象接口的定义,该类型就至关因而Component类型,是饺子馅,须要装饰的,须要包装的 5 /// </summary> 6 public abstract class House 7 { 8 //房子的装修方法--该操做至关于Component类型的Operation方法 9 public abstract void Renovation(); 10 } 11 12 /// <summary> 13 /// 该抽象类就是装饰接口的定义,该类型就至关因而Decorator类型,若是须要具体的功能,能够子类化该类型 14 /// </summary> 15 public abstract class DecorationStrategy:House //关键点之二,体现关系为Is-a,有这这个关系,装饰的类也能够继续装饰了 16 { 17 //经过组合方式引用Decorator类型,该类型实施具体功能的增长 18 //这是关键点之一,包含关系,体现为Has-a 19 protected House _house; 20 21 //经过构造器注入,初始化平台实现 22 protected DecorationStrategy(House house) 23 { 24 this._house=house; 25 } 26 27 //该方法就至关于Decorator类型的Operation方法 28 public override void Renovation() 29 { 30 if(this._house!=null) 31 { 32 this._house.Renovation(); 33 } 34 } 35 } 36 37 /// <summary> 38 /// PatrickLiu的房子,我要按个人要求作房子,至关于ConcreteComponent类型,这就是咱们具体的饺子馅,我我的比较喜欢韭菜馅 39 /// </summary> 40 public sealed class PatrickLiuHouse:House 41 { 42 public override void Renovation() 43 { 44 Console.WriteLine("装修PatrickLiu的房子"); 45 } 46 } 47 48 49 /// <summary> 50 /// 具备安全功能的设备,能够提供监视和报警功能,至关于ConcreteDecoratorA类型 51 /// </summary> 52 public sealed class HouseSecurityDecorator:DecorationStrategy 53 { 54 public HouseSecurityDecorator(House house):base(house){} 55 56 public override void Renovation() 57 { 58 base.Renovation(); 59 Console.WriteLine("增长安全系统"); 60 } 61 } 62 63 /// <summary> 64 /// 具备保温接口的材料,提供保温功能,至关于ConcreteDecoratorB类型 65 /// </summary> 66 public sealed class KeepWarmDecorator:DecorationStrategy 67 { 68 public KeepWarmDecorator(House house):base(house){} 69 70 public override void Renovation() 71 { 72 base.Renovation(); 73 Console.WriteLine("增长保温的功能"); 74 } 75 } 76 77 public class Program 78 { 79 static void Main() 80 { 81 //这就是咱们的饺子馅,须要装饰的房子 82 House myselfHouse=new PatrickLiuHouse(); 83 84 DecorationStrategy securityHouse=new HouseSecurityDecorator(myselfHouse); 85 securityHouse.Renovation(); 86 //房子就有了安全系统了 87 88 //若是我既要安全系统又要保暖呢,继续装饰就行 89 DecorationStrategy securityAndWarmHouse=new HouseSecurityDecorator(securityHouse); 90 securityAndWarmHouse.Renovation(); 91 } 92 } 93 }
写了不少备注,你们好好体会一下,里面有两个关键点,仔细把握。
3、装饰模式的实现要点:
一、经过采用组合、而非继承的手法,Decorator模式实现了在运行时动态地扩展对象功能的能力,并且能够根据须要扩展多个功能。避免了单独使用继承带来的“灵活性差”和“多子类衍生问题”。
二、Component类在Decorator模式中充当抽象接口的角色,不该该去实现具体的行为。并且Decorator类对于Component类应该透明——换言之Component类无需知道Decorator类,Decorator类是从外部来扩展Component类的功能。
三、Decorator类在接口上表现为is-a Component的继承关系,即Decorator类继承了Component类所具备的接口。但在实现上又表现为has-a Component的组合关系,即Decorator类又使用了另一个Component类。咱们可使用一个或者多个Decorator对象来“装饰”一个Component对象,且装饰后的对象仍然是一个Component对象。
四、Decorator模式并不是解决“多子类衍生的多继承”问题,Decorator模式应用的要点在于解决“主体类在多个方向上的扩展功能”——是为“装饰”的含义。
3.1】、装饰模式的优势:
(1)、把抽象接口与其实现解耦。
(2)、抽象和实现能够独立扩展,不会影响到对方。
(3)、实现细节对客户透明,对用于隐藏了具体实现细节。
3.2】、装饰模式的缺点:
(1)、增长了系统的复杂度
3.3】、在如下状况下应当使用桥接模式:
(1)、若是一个系统须要在构件的抽象化角色和具体化角色之间添加更多的灵活性,避免在两个层次之间创建静态的联系。
(2)、设计要求实现化角色的任何改变不该当影响客户端,或者实现化角色的改变对客户端是彻底透明的。
(3)、须要跨越多个平台的图形和窗口系统上。
(4)、一个类存在两个独立变化的维度,且两个维度都须要进行扩展。
4、.NET 中装饰模式的实现
在Net框架中,有一个类型很明显的使用了“装饰模式”,这个类型就是Stream。Stream类型是一个抽象接口,它在System.IO命名空间里面,它其实就是Component。FileStream、NetworkStream、MemoryStream都是实体类ConcreteComponent。右边的BufferedStream、CryptoStream是装饰对象,它们都是继承了Stream接口的。java
如图:
设计模式
Stream就至关于Component,定义装饰的对象,FileStream就是要装饰的对象,BufferedStream是装饰对象。咱们看看BufferedStream的定义,部分定义了。安全
1 public sealed class BufferedStream : Stream 2 { 3 private const int _DefaultBufferSize = 4096; 4 5 private Stream _stream;
结构很简单,对比结构图看吧,没什么可说的了。框架