GOF之装饰模式

问题的引入:

假如我们需要为游戏开发一种坦克,除了各种不同型号的坦克外,我们还希望在不同场合中为其增加以下一种或多种功能:比如红外线夜视功能,水陆双栖功能,卫星定位功能等等。

通过子类继承发现代码冗余太严重

动机(Motivation)

上述描述的问题根源在于我们“过度的使用了继承来扩展对象的功能”,由于继承为类型引入的静态特质,使得这种扩展方式缺乏灵活性;并且随着子类的增多(扩展功能的增多),各种子类的组合(扩展功能的组合)会导致更多子类的膨胀(多继承)。

如何使“对象功能的扩展”能够根据需要来动态地实现?同时避免“扩展功能的增多”带来的子类膨胀问题?从而使得任何“功能扩展变化”所导致的影响将为最低?

意图(Intent)

动态地给一个对象增加一些额外的职责。就增加功能而言,Decorator模式比生成子类更为灵活。

结构(Structure)

代码实现:

 1 装饰的抽象类和实体类
 2 public abstract class Decorator:Tank
 3     {
 4         protected Tank tank;
 5         public Decorator(Tank tank)
 6         {
 7             this.tank = tank;
 8         }
 9 
10 
11         public override void Run()
12         {
13             tank.Run();
14         }
15 
16         public override void Shot()
17         {
18             tank.Shot();
19         }
20     }
21 
22     public class DecoratorA : Decorator
23     {
24         public DecoratorA(Tank tank)
25             : base(tank)
26         { }
27         public override void Run()
28         {
29             Console.Write("带红外功能的");
30             base.Run();
31         }
32         public override void Shot()
33         {
34             Console.Write("带红外功能的");
35             base.Shot();
36         }
37     }
38     public class DecoratorB : Decorator
39     {
40         public DecoratorB(Tank tank)
41             : base(tank)
42         { }
43         public override void Run()
44         {
45             Console.Write("带水陆双栖功能的");
46             base.Run();
47         }
48         public override void Shot()
49         {
50             Console.Write("带水陆双栖功能的");
51             base.Shot();
52         }
53     }
54     public class DecoratorC : Decorator
55     {
56         public DecoratorC(Tank tank)
57             : base(tank)
58         { }
59         public override void Run()
60         {
61             Console.Write("带卫星定位功能的");
62             base.Run();
63         }
64         public override void Shot()
65         {
66             Console.Write("带卫星定位功能的");
67             base.Shot();
68         }
69     }
 1 需要被装饰的对象的抽象类和实体类
 2  public abstract class Tank
 3     {
 4         public abstract void Run();
 5         public abstract void Shot();
 6     }
 7     public class T50 : Tank
 8     {
 9 
10         public override void Run()
11         {
12             Console.Write("T50运行");
13         }
14 
15         public override void Shot()
16         {
17             Console.Write("T50攻击");
18         }
19     }
20     public class T75 : Tank
21     {
22 
23         public override void Run()
24         {
25             Console.Write("T75运行");
26         }
27 
28         public override void Shot()
29         {
30             Console.Write("T75攻击");
31         }
32     }
33 
34     public class T90 : Tank
35     {
36 
37         public override void Run()
38         {
39             Console.Write("T90运行");
40         }
41 
42         public override void Shot()
43         {
44             Console.Write("T90攻击");
45         }
46     }
 1 主函数的调用
 2  static void Main(string[] args)
 3         {
 4             Tank tank = new T75();
 5             DecoratorA da = new DecoratorA(tank);
 6             DecoratorB db = new DecoratorB(da);
 7             DecoratorC dc = new DecoratorC(db);
 8             dc.Run();
 9             Console.WriteLine();
10             dc.Shot();
11             Console.ReadKey();
12         }

Decorator模式的几个要点:

通过采用组合、而非继承的手法,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模式应用的要点在于解决“主体类在多个方向上的扩展功能”--是为“装饰的含义”。

.NET框架中的Decorator应用:

 

posted @ 2016-11-07 17:15  朴树的扑  阅读(300)  评论(0编辑  收藏  举报