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应用: