装饰模式是为已有功能动态地添加更多功能的一种模式。当系统需要新功能时,一般做法是向旧的类中添加新的代码,这些新加的代码通常影响了原有类的核心职责或行为,在主类中加入新的字段、方法或是逻辑,从而增加了主类的复杂性,而这些新加入的代码仅仅是为了满足一些只在某种特定情况下才会发生的特殊行为的需要。装饰模式提供了一个非常好的解决方案,它把每个要装饰的功能放在单独的类中,并让这个类包装它所有要装饰的对象,这样当需要执行特殊行为时,客户代码就可以在运行时根据需要有选择性地,按顺序的使用装饰功能包装的对象了。
装饰模式在现实生活中随处可见。比如我们买了一辆车,然后我们第一件要做的事,就是把自己的爱车装饰一下。可供选择的配件包括ABS刹车防抱死系统,车载音响,倒车雷达等等,可以选择其中的一件或是多件来装饰我们的爱车。把上述场景转化为程序如下:
有一个MyCarDecorate类,就是一辆裸车。要实现对裸车的装饰,有如下两种方法:
1.在MyCarDecorate里面添加相应的方法。这种做法显然不对。一来违反了面向对象的开放-封闭原则,二来也不易扩展。试想一下,如果每个用户都有不同的需求,那你这个类不是每次调用前都要修改一次吗?
2.使用子类继承的方法。比如用户需要裸车+倒车雷达,则添加一个新类Radar,继承MyCarDecorate;如果用户需要裸车+雷达+音响,则再新加一个Audio类,继承Radar;如果用户只需要裸车+音响,则还需要添加一个新类AudioOnly类,继承自MyCarDecorate…………。看似好像解决了问题,但如果配件有上百种,那么你的子类数量就会呈指数形式增长。所以这种做法也不可取。
下面就用本节的主角,装饰模式来解决这个难题吧。 为了把车内装饰同车本身分离开,我们要用到一个Show接口,定义如下: public interface ICarShowHandle { void Show(); } MyCarDecorate裸车类继承ICarShowHandle接口 public class MyCarDecorate : ICarShowHandle { private string _carName; public MyCarDecorate() { } public MyCarDecorate(string carName) { this._carName = carName; } public void Show() { Console.WriteLine(string.Format("这就是我的{0}小车", _carName)); } } 为了把裸车的代码同装饰分离,我们需要一个汽车装饰的基类,同样需要继承自ICarShowHandle public class CarTrim : ICarShowHandle { private ICarShowHandle _myCar; public CarTrim(ICarShowHandle myCar) { this._myCar = myCar; } public virtual void Show() { if (_myCar != null) _myCar.Show(); } } 下面就是让各种装饰一一继承上面这个汽车装饰类。 public class CarRadar : CarTrim { public CarRadar(ICarShowHandle myCar) : base(myCar) { } public override void Show() { Console.WriteLine("具有倒车雷达的功能"); base.Show(); } } public class CarAudio : CarTrim { public CarAudio(ICarShowHandle myCar) : base(myCar) { } public override void Show() { Console.WriteLine("具有车载音响系统"); base.Show(); } } public class CarABS:CarTrim { public CarABS(ICarShowHandle myCar) : base(myCar) { } public override void Show() { Console.WriteLine("具有ABS刹车防抱死系统"); base.Show(); } }
调用方法如下:
1.ICarShowHandle myCar = new CarABS(new CarRadar(new CarAudio(new MyCarDecorate("飞度")))); myCar.Show();
显示结果为:
2.ICarShowHandle myCar = new CarABS(new CarRadar(new MyCarDecorate("宝马"))); myCar.Show();
显示结果为:
如需转载,请注明本文原创自CSDN TJVictor专栏:http://blog.csdn.net/tjvictor