本笔记摘抄自:http://www.javashuo.com/article/p-oojsxwfr-gm.html,记录一下学习过程以备后续查用。html
1、引言设计模式
今天咱们要讲结构型设计模式的第三个模式--装饰模式。当第一次看到这个名称时想到的是另一个词语“装修”,我的观点谈谈对“装修”的理解吧,请你们安全
看清楚如今说是“装修”而不是“装饰”。当咱们长大了就要准备结婚(男大当婚女大当嫁嘛),而结婚每每涉及到要买房的事。若是买的是毛坯房,假如想要房框架
子的内饰是大理石风格的,咱们只需在毛坯房的基础之上用大理石风格的材料装修就能够(不须要从新盖房)。房子装修好了住了进来很开心,过了段时间,ide
发现房子在冬季比较冷,因而就想给房子增长保暖的功能,此时咱们只需在房子里面增长采暖系统(南方人使用变频空调)。又过了一段时间,老是有陌生模块化
人光顾,因而想给房子增长安防设备,此时咱们能够在门口及室内加装监控摄像头(或者加红外、门磁等布控)及安装防盗网。随着时间的流逝,咱们可能学习
会根据咱们的需求增长相应的功能,而在此期间,咱们的房子都是能够正常使用的,从这一方面来说,“装修”和“装饰”有相似的概念。下面让咱们看看装饰模spa
式具体是什么吧?设计
2、装饰模式介绍3d
装饰模式:英文名称--Decorator Pattern;分类--结构型。
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 、装饰模式的具体实现
继续拿房子的例子来讲吧:
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 } }
写了不少备注,你们好好体会一下,里面有两个关键点,仔细把握。
运行结果以下:
3、装饰模式的实现要点
1)经过采用组合而非继承的手法,Decorator模式实现了在运行时动态地扩展对象功能的能力,能够根据须要扩展多个功能,避免了单独使用继承带来的
“灵活性差”和“多子类衍生问题”。
2)Component类在Decorator模式中充当抽象接口的角色,不该该去实现具体的行为,并且Decorator类对于Component类应该透明--换言之Component类
无需知道Decorator类,Decorator类是从外部来扩展Component类的功能。
3)Decorator类在接口上表现为Is-A Component的继承关系,即Decorator类继承了Component类所具备的接口,但在实现上又表现为Has-A Component
的组合关系,即Decorator类又使用了另一个Component类。咱们可使用一个或者多个Decorator对象来“装饰”一个Component对象,且装饰后的对象仍然
是一个Component对象。
4)Decorator模式并不是解决“多子类衍生的多继承”问题,Decorator模式应用的要点在于解决“主体类在多个方向上的扩展功能”--是为“装饰”的含义。
3.一、装饰模式的优势
1)把抽象接口与其实现解耦。
2)抽象和实现能够独立扩展,不会影响到对方。
3)实现细节对客户透明,对用于隐藏了具体实现细节。
3.二、装饰模式的缺点
1)增长了系统的复杂度
3.三、在如下状况下应当使用桥接模式
1)若是一个系统须要在构件的抽象化角色和具体化角色之间添加更多的灵活性,避免在两个层次之间创建静态的联系。
2)设计要求实现化角色的任何改变不该当影响客户端,或者实现化角色的改变对客户端是彻底透明的。
3)须要跨越多个平台的图形和窗口系统上。
4)一个类存在两个独立变化的维度,且两个维度都须要进行扩展。
4、.NET中装饰模式的实现
在Net框架中,有一个类型很明显使用了“装饰模式”,这个类型就是Stream。Stream类型是一个抽象接口,它在System.IO命名空间里面,它其实就是
Component。FileStream、NetworkStream、MemoryStream都是实体类ConcreteComponent。右边的BufferedStream、CryptoStream是装饰对象,它们都是
继承了Stream接口。
Stream就至关于Component,定义装饰的对象,FileStream就是要装饰的对象,BufferedStream是装饰对象。
咱们看看BufferedStream的部分定义:
public sealed class BufferedStream : Stream { private const int _DefaultBufferSize = 4096; private Stream _stream; //…… }
结构很简单,对比结构图看吧。
5、总结
这个模式有点像包饺子,ConcreteComponent实际上是饺子馅,Decorator就像饺子皮同样,包什么皮就有什么的样子,皮和皮也能够嵌套,固然咱们生活中
的饺子只是包一层皮。其实手机也是一个装饰模式使用的好例子,早期的手机只有接打电话的功能,而后能够发短信和彩信,再后能够拍照了。如今的手机功
能很丰富,其结果也相似装饰的结果。随着社会的进步和技术发展,模块化的手机也出现了,其设计原理愈来愈接近“装饰模式”。不光是手机,咱们身边的很
多家用电器也有相似的发展经历,让咱们努力发现生活中的真理吧,而后再在软件环境中慢慢体会。