装饰器模式属于结构性设计模式中的一种,装饰器模式的主要为了在不修改原有类的功能的情况下,为原有的类新增功能。
为原有的类新增功能,继承也是可以实现的,当装饰器模式除了能增加新功能之外,还可以随机组合功能的顺序,而继承的实现方式,功能的执行的顺序是固定的。当然,装饰器模式也有缺点,代码实现会比继承实现方式复杂,而且不易理解和看懂。
下面用一个例子来说大家阐述一下装饰器模式(Decorator)
Product类用来实现用户产品的开通的功能,现在有个新的需求,用户在开通产品前,先检查产品是否有库存、用户账户有足够的余额开通产品,产品开通成功后,需要跟踪产品发货情况。
public class Product { public virtual void ProductOpen() { Console.WriteLine("产品开通"); } }根据上面的需求,我们需要增加三个功能;在开通产品前,需要增加库存检查和余额检查功能,在产品开通后,需要增加发货跟踪功能。下面我们先用装饰器模式的来实现。
第一步:先增加一个装饰器基类:BaseDecoratorProduct,如下图所示:BaseDecoratorProduct类基础Product类,一个带参数的构造函数,参数类型是Product,重写父类ProductOpen方法。
public class BaseDecoratorProduct : Product { protected Product _Propduct = null; public BaseDecoratorProduct(Product product) { this._Propduct = product; } public override void ProductOpen() { this._Propduct.ProductOpen(); } }第二步:新增库存检查类RenewDecoratorProduct,如下图所示:RenewDecoratorProduct类继承BaseDecoratorProduct,一个带参数的构造函数,参数类型是Product,重写父类的ProductOpen方法,在ProductOpen方法在实现库存检测的功能,再调用父类的ProductOpen方法,如下图的base.ProductOpen()
public class RenewDecoratorProduct:BaseDecoratorProduct { public RenewDecoratorProduct(Product product) : base(product) { } public override void ProductOpen() { Console.WriteLine("检查产品是否可以开通"); base.ProductOpen(); } }第三步:新增库存检查类PayDecoratorProduct,如下图所示:PayDecoratorProduct类继承BaseDecoratorProduct,一个带参数的构造函数,参数类型是Product,重写父类的ProductOpen方法,在ProductOpen方法在实现账户余额检测的功能,再调用父类的ProductOpen方法,如下图的base.ProductOpen() public class PayDecoratorProduct:BaseDecoratorProduct { public PayDecoratorProduct(Product product) :base(product) { } public override void ProductOpen() { Console.WriteLine("检查用户账号余额是否足够开通产品"); base.ProductOpen(); } }第四步:新增库存检查类SourseDecoratorProduct,如下图所示:SourseDecoratorProduct类继承BaseDecoratorProduct,一个带参数的构造函数,参数类型是Product,重写父类的ProductOpen方法,先调用父类的ProductOpen方法,如下图的base.ProductOpen(),再实现发货跟踪功能。 public class SourceDecoratorProduct:BaseDecoratorProduct { public SourceDecoratorProduct(Product product) : base(product) { } public override void ProductOpen() { base.ProductOpen(); Console.WriteLine("产品开发成功后,发货操作"); } }第五步:从第一到四步,装饰器模式的实现已经完成,接下就是调用了,调用代码如下;我们的业务逻辑是先检查库存,再检查余额,开通产品,发货,先实例化Product实例,逐步实例化库存检查,余额检测,发货跟踪,我们执行一下,看看结果。
static void Decorator() { Console.WriteLine("************执行开始**************"); Product product = new Product(); product = new RenewDecoratorProduct(product); product = new PayDecoratorProduct(product); product = new SourceDecoratorProduct(product); product.ProductOpen(); Console.WriteLine("************执行结束**************"); Console.ReadKey(); }执行结果如下:先出现余额检测,接着是库存检查,开通产品,发货跟踪,我们来分析一下执行结果:
装饰器子类重写的ProductOpen方法,只要在base.ProductOpen之前写的逻辑,都会在ProductOpen之前就被执行,而且执行顺序和实例化的顺序相反,即是倒过来了,但是只要在base.ProductOpen之前后写的逻辑,执行顺着则和实现话顺序相同的。到这里装饰器模式的实现基本上就讲完了。
上面的装饰器模式实现的功能,其实完全可以用一个类来继承Product类来实现的。不需要像上面那么麻烦的实现,要写那个多的类和方法,还不容易理解。如下图显示:
public class ProductExtend : Product { public override void ProductOpen() { Console.WriteLine("检查用户账号余额是否足够开通产品"); Console.WriteLine("检查产品是否可以开通"); base.ProductOpen(); Console.WriteLine("产品开发成功后,发货操作"); } }通过上图的继承方式,完全可以实现装饰器模式实现的功能,那我们为什么还要用装饰器模式来实现呢?这里做一个简单的解释:当你用户的渠道不一样时,库存检查,余额检测这两个功能的执行顺序不一样时,那么继承方式实现的方式就不适合了,装饰器更加适合实现,他可以根据不用的用户渠道来随机组合功能的执行顺序,或者有些用户渠道不需要检测余额时,装饰器模式就非常适合解决这类的问题,继承的方式就有心无力了。
选择什么的方式来实现,必须要结合具体的业务需求,不要为了使用设计模式使用,一定要选择合理的方式去实现。
