装饰模式适合的最恰当的形容词就是:子类复子类,子类何其多。 如果一个基类有多个子类,而各个子类可能具有不同的功能,同一个子类也可能具有不同的功能,如果我们将一个功能定义为实现一个接口,那么同一个子类要实现不同的功能,那么他要在子类的基础上继续创建子类,无穷无尽。。。
例子使用:坦克分为T50与T75,坦克具有基本的发射与移动功能,其中具有附加功能(红外功能、水陆两栖功能、卫星定位功能)
如果我们不使用装饰模式的话,那么我们实现的代码:
#region 抽象坦克基类 public abstract class Tank { public abstract void Shot(); public abstract void Run(); } #endregion
#region 具体坦克类 public class Tank50 : Tank { public override void Run() { Console.WriteLine(this.GetType().Name+"在奔跑"); } public override void Shot() { Console.WriteLine(this.GetType().Name + "在发射炮弹"); } } public class Tank75 : Tank { public override void Run() { Console.WriteLine(this.GetType().Name + "在奔跑"); } public override void Shot() { Console.WriteLine(this.GetType().Name + "在发射炮弹"); } } #endregion
#region 功能接口 interface IRedLine { void RedLine(); } interface IWaterPath { void WaterPath(); } interface IPosition { void IPosition(); } #endregion
#region 功能坦克类 public class Tank50A : Tank50, IRedLine { public void RedLine() { Console.WriteLine("具有红外功能"); } } public class Tank50B : Tank50, IRedLine,IWaterPath { public void RedLine() { Console.WriteLine("具有红外功能"); } public void WaterPath() { Console.WriteLine("具有水陆两栖功能"); } } //无限扩展 //...... #endregion
装饰模式避免了这种问题,它的设计思路不是将功能化为接口,而是将每个功能实现在每个装饰类中。
坦克类仍然不变,如下:
#region 抽象坦克基类 public abstract class Tank { public abstract void Shot(); public abstract void Run(); } #endregion
#region 具体坦克类 public class Tank50 : Tank { public override void Run() { Console.WriteLine(this.GetType().Name+"在奔跑"); } public override void Shot() { Console.WriteLine(this.GetType().Name + "在发射炮弹"); } } public class Tank75 : Tank { public override void Run() { Console.WriteLine(this.GetType().Name + "在奔跑"); } public override void Shot() { Console.WriteLine(this.GetType().Name + "在发射炮弹"); } } #endregion
装饰类如下:
#region 装饰基类 public abstract class Decorator :Tank { private Tank _tank; public Decorator(Tank tank) { _tank = tank; } public override void Run() { _tank.Run(); } public override void Shot() { _tank.Shot(); } } #endregion
#region 具体功能装饰类 public class DecoratorRedLine : Decorator { public DecoratorRedLine(Tank tank) : base(tank) { } public override void Run() { base.Run(); } public override void Shot() { Console.WriteLine("具有红外功能"); base.Shot();//这里就是重点!!!!可以调用构造函数实例时的基成员方法 } } public class DecoratorWaterPath : Decorator { public DecoratorWaterPath(Tank tank) : base(tank) { } public override void Run() { base.Run(); } public override void Shot() { Console.WriteLine("具有水陆两栖功能"); base.Shot(); } } public class DecoratorPosition : Decorator { public DecoratorPosition(Tank tank) : base(tank) { } public override void Run() { base.Run(); } public override void Shot() { Console.WriteLine("具有定位功能"); base.Shot(); } } #endregion
static void Main(string[] args) { Tank tank = new Tank50();//实例化一个坦克类 Decorator decorator = new DecoratorRedLine(tank); Decorator decorator2 = new DecoratorWaterPath(decorator);//这个shot时会调用decorator的shot,从而实现不断叠加 decorator2.Shot(); Console.ReadKey(); }
装饰类,将各个需要随时变化的功能写在装饰的子类中,当需要使用的时候只需要调用相应的装饰子类,重点就是调用base.shot() base的方法 ,因此在装饰的抽象类中,必须调用对需要装饰类的方法的复写,这样才能实现base的方法!
设计模式的思想真的是非常好,多学,多做,多练,加油!