解读设计形式—-装饰情势(Decorator Pattern)

    
通过共性的悬空和一多样的新效率职责的点缀,新的规划应运而生,现在一经我们需要扩展出一种新的笔种,要求出了具有基本的写行为之外,还同时含有可安装字体大小和字体颜色的效应。分明,我们前边的计划就派上了用场,那时大家只需要经过集合的法子就可知组合成这一种新的角色(笔种)出来。很明确应用了Decorator让规划变得更加灵活,同时也表达了一个题目,在咱们实在的宏图中,应少用继承多,尽量的通过汇聚的章程来设计,提升规划灵活度。
透过结合设计出的新的笔种:

UML图:
                               
图片 1

BoldPen类的宏图:

    
如若大家需要为该笔添加新的职责,让其得以调整字体大小(这样的以身作则好象有点不适合实际哈,此处只是通过这些虚有的对象来演示Decorator,暂不考虑现实题材),则可以定义一子类继承于Pen,然后重写Write方法。

六、本文参考资料       张逸  《软件设计精要与格局》  电子工业出版社
      MSDN
WebCast 《C#面向对象设计形式纵横谈(10)
Decorator装饰格局(结构型格局)》

 1图片 2namespace DesignPattern.Decorator
 2图片 3图片 4图片 5{
 3图片 6图片 7    /**//// <summary>
 4图片 8    /// 实现IWrite接口
 5图片 9    /// </summary>
 6图片 10    public class Pen:IWrite
 7图片 11图片 12    图片 13{
 8图片 14        public string Write()
 9图片 15图片 16        图片 17{
10图片 18            return “能写的笔”;
11图片 19        }
12图片 20    }
13图片 21}
14图片 22

1图片 23namespace DesignPattern.Decorator
2图片 24图片 25图片 26{
3图片 27    public interface IWrite
4图片 28图片 29    图片 30{
5图片 31        string Write();
6图片 32    }
7图片 33}
8图片 34

四、完善Decorator的设计      此部分自己就不多说了,代码也早已在下边体现出。示例运行结果:
     图片 35

     以上的实在完全符合装饰格局的企图“不改动原来的行事动态地给一个对象添加一些新的功力”。想想,这样的规划美好吗?现在需要变动,要求这种笔出了能写之外还要还拥有可以安装字体大小及字体颜色的装置效能,按继承机制的思索来计划是不是相应继承BlodPen然后又重写Write方法吗?这样下来就形成了一个多子类的延伸的比比皆是继承连串,最后出现的问题就是类无限的增多,既所谓的类爆炸。
   
三、重构Decorator的设计      
要缓解上述出现类爆炸的题材该肿么办吧?仔细察看就会发现,通过连续子类在添加新的任务的时候都亟待重写Write方法才能实现,这大家是不是应有重构一下,抽象出共性呢?答案是大势所趋的,我们完全可以把Write方法抽象为接口或抽象类,通过架空后大家得以经过汇集的点子动态的组成新的效用职责。重构后的计划如下:
接口的肤浅:

  ———————————————————————————————————-

五、Decorator情势的中央思想
     
通过行使组合,而非继承手法,Decorator格局实现了在运转时动态地增加对象效能的作为,而且可以遵照需要扩展三个功用,避免了单独使用持续所带动“灵活性差”和“类爆炸”等问题。把不同的职责封装在不同的职责类的个体方法或性能中,那样对内开放,对外封闭。符合面向对象的“单一任务”和“开放–封闭”原则;同时也很好的符合面向对象设计基准中的“优先采纳对象组合而非继承”。

Pen类的宏图:

     
装饰形式(Decorator)也叫包装器形式(Wrapper)。以“装饰”的意义生动形象地勾画了“动态地给一个对象添加一些外加的任务”的来意。GOF在《设计格局》一书中提交的概念为:动态地给一个目的添加一些额外的任务。装饰格局充裕利用了继承和聚集的优势,创制出无与论比的宏图美学。就充实效果来说,Decorator形式比较生成子类更为灵活。

二、迎接Decorator的到来
     
例如我们要为一只“笔”来规划其作为。从我们拥有的面向对象的学识出发,为一个目的的本来艺术添加新的任务,可以通过连续机制,从写基类方法来实现,此时父类方法应为虚方法或是抽象方法。

一、使用Decorator形式的动机      
现在有诸如此类一个场景,要求大家为一个对象动态增长新的天职,这一个任务并不改动原有的行事,而是在原来行为的基础上添加新的效能,就好比咱们在吃薯条的时候涂上特别美味的番茄汁一般。
    
从面向对象的角度来说,我们要为一个对象添加一新的职责完全可以行使连续机制来实现,不过这么的计划性会造成一个问题,“过度地使用持续来扩张对象的效用”由于持续为品种引入的静态特质,使得这种扩展情势不够灵活性;并且随着字类的充实(扩展效用的增多),各类子类的结缘(扩张功效的咬合)会招致更多子类的膨胀,也就是所谓的类爆炸。怎样使“对象效能的壮大”可以依照需要来动态地实现同时又防止“扩大效率的扩展”带来的类爆炸问题?从而使得其他“效用扩张变化”所造成的影响将为压低?

 1图片 36namespace DesignPattern.Decorator
 2图片 37图片 38图片 39{
 3图片 40    public class Pen
 4图片 41图片 42    图片 43{
 5图片 44        public virtual string Write()
 6图片 45图片 46        图片 47{
 7图片 48            return “普通的笔”;  
//只可以进展最基本的写操作
 8图片 49        }
 9图片 50    }
10图片 51}

 1图片 52namespace DesignPattern.Decorator
 2图片 53图片 54图片 55{
 3图片 56    public class BoldColorPen:IWrite
 4图片 57图片 58    图片 59{
 5图片 60        private List<IWrite> list=null;
 6图片 61        public BoldColorPen()
 7图片 62图片 63        图片 64{ }
 8图片 65
 9图片 66        public BoldColorPen(List<IWrite> list)
10图片 67图片 68        图片 69{
11图片 70            this.list = list;
12图片 71        }
13图片 72        public string Write()
14图片 73图片 74        图片 75{
15图片 76            string str = string.Empty;
16图片 77            for (int i = 0; i < list.Count; i++)
17图片 78图片 79            图片 80{
18图片 81                str += ((IWrite)list[i]).Write() + ” “;
19图片 82            }
20图片 83            return str;
21图片 84        }
22图片 85
23图片 86        private string Other()
24图片 87图片 88        图片 89{
25图片 90           //同样我们还可为其增长自己的任务
26图片 91        }
27图片 92    }
28图片 93}
29图片 94

 1图片 95namespace DesignPattern.Decorator
 2图片 96图片 97图片 98{
 3图片 99    public class BoldPen:IWrite
 4图片 100图片 101    图片 102{
 5图片 103        IWrite component = null;
 6图片 104        int borderWidth = 0;
 7图片 105
 8图片 106图片 107        public BoldPen() 图片 108{ }
 9图片 109
10图片 110        public BoldPen(IWrite compontent, int borderWidth)
11图片 111图片 112        图片 113{
12图片 114            this.component = compontent;
13图片 115            this.borderWidth = borderWidth;
14图片 116        }
15图片 117
16图片 118图片 119        /**//// <summary>
17图片 120        /// 接口方法
18图片 121        /// </summary>
19图片 122        public string Write()
20图片 123图片 124        图片 125{
21图片 126            //调用接口方法
22图片 127            string pen = this.component.Write();
23图片 128            return pen + ” 字体大小:” + this.borderWidth.ToString();
24图片 129        }
25图片 130
26图片 131图片 132        /**//// <summary>
27图片 133        /// 装饰方法
28图片 134        /// </summary>
29图片 135        /// <param name=”borderWidth”></param>
30图片 136        public void SetBorderWidth(int borderWidth)
31图片 137图片 138        图片 139{
32图片 140            this.borderWidth = borderWidth;
33图片 141        }
34图片 142    }
35图片 143}

 1图片 144namespace DesignPattern.Decorator
 2图片 145图片 146图片 147{
 3图片 148
 4图片 149    public class BoldPen : Pen
 5图片 150图片 151    图片 152{
 6图片 153        public override string Write()
 7图片 154图片 155        图片 156{
 8图片 157            return base.Write() + FontSize();
 9图片 158        }
10图片 159
11图片 160        private string FontSize()
12图片 161图片 162        图片 163{
13图片 164            return “字体大小:10px”;
14图片 165        }
15图片 166    }
16图片 167}

    
如上的计划性通过架空出接口方法Write,不同的效用组件去继承实现IWrite接口实现Write方法,通过特定的属性或措施(我们得以叫它装饰艺术)把温馨的任务封装在和谐的内部,这样的宏图也完全符合面向对象的纯粹任务设计思想。