设计模式—装饰器模式(Decorator)

装饰器模式属于结构性设计模式中的一种,装饰器模式的主要为了在不修改原有类的功能的情况下,为原有的类新增功能。

为原有的类新增功能,继承也是可以实现的,当装饰器模式除了能增加新功能之外,还可以随机组合功能的顺序,而继承的实现方式,功能的执行的顺序是固定的。当然,装饰器模式也有缺点,代码实现会比继承实现方式复杂,而且不易理解和看懂。

下面用一个例子来说大家阐述一下装饰器模式(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之前后写的逻辑,执行顺着则和实现话顺序相同的。到这里装饰器模式的实现基本上就讲完了。

设计模式—装饰器模式(Decorator)_第1张图片


上面的装饰器模式实现的功能,其实完全可以用一个类来继承Product类来实现的。不需要像上面那么麻烦的实现,要写那个多的类和方法,还不容易理解。如下图显示:

public class ProductExtend : Product
    {
        public override void ProductOpen()
        {
            Console.WriteLine("检查用户账号余额是否足够开通产品");
            Console.WriteLine("检查产品是否可以开通");
            base.ProductOpen();
            Console.WriteLine("产品开发成功后,发货操作");
        }
    }

通过上图的继承方式,完全可以实现装饰器模式实现的功能,那我们为什么还要用装饰器模式来实现呢?这里做一个简单的解释:当你用户的渠道不一样时,库存检查,余额检测这两个功能的执行顺序不一样时,那么继承方式实现的方式就不适合了,装饰器更加适合实现,他可以根据不用的用户渠道来随机组合功能的执行顺序,或者有些用户渠道不需要检测余额时,装饰器模式就非常适合解决这类的问题,继承的方式就有心无力了。

选择什么的方式来实现,必须要结合具体的业务需求,不要为了使用设计模式使用,一定要选择合理的方式去实现。




你可能感兴趣的:(设计模式)