Fork me on GitHub

.NET简谈设计模式之(装饰者模式性能问题?)

我假设看这篇文章的朋友对装饰者模式都能有各自的、深入的理解。因为这篇文章是讨论装饰者模式的性能问题。

在本人的“.NET简谈设计模式之(装饰者模式)”一文中比较详细的讲解了装饰者模式的一般应用,但是我总是感觉装饰者模式隐隐约约之中有点不完美。经过我昨天一整天的思考、推敲终于找到了它隐隐约约中的那点不完美是什么,为了行为去继承带来的无辜的性能开销。所以本人想把它写出来,跟大家讨论下装饰者模式的性能该如何平衡。是用时间换空间还是用空间换时间,这里的时间就是我们开发的效率时间。

首先回顾一下装饰者模式诞生的本意是什么,它的官方意思是:动态地给一个对象添加一些额外的职责。我们都知道给对象扩展功能是通过继承来实现,但是继承有它的不好之处,比如:子类与父类之间的耦合、子类的无限扩大等等。而装饰者模式就是想利用动态的给需要扩展的对象添加功能。将需要扩展的动能独立起来,作为一个个装饰类,在需要的时候给对象穿上这个装饰。

1:

这张类图照这个样子发展下去不得了,子类无限膨胀,后面需求谁都不知道。这是我们一般扩展对象的正常方法,我们来看一下装饰者模式的原型。

2:

将需要扩展的功能独立起来,当需要的时候动态的添加功能。我想这就是装饰者名称由来,将后期扩展的功能比喻成装饰者,是很形象。

但是当我们带着这张图的原理去看代码的时候,它的结构根本不是这样的“干净”。所以说理论与实践是分不开的。请看代码:

using System;
using System.Collections.Generic;
using System.Text;

namespace ConsoleApplication2
{
    public class ConcreteConpontent
    {
        public virtual void Operation()
        {
            Console.WriteLine("顶级待装饰对象");
        }
        public virtual void Message()
        {
            Console.WriteLine("顶级对象消息");
        }
    }

    public abstract class Decorator : ConcreteConpontent
    {
        protected ConcreteConpontent m_compontent;
        public void SetCompontent(ConcreteConpontent com)
        {
            m_compontent = com;
        }
    }
    public class ConcreteDecoratorA : Decorator
    {
        public override void Operation()
        {
            m_compontent.Operation();
            Console.WriteLine("ConcreteDecoratorA进行了方法的动态添加");
        }
        public override void Message()
        {
            m_compontent.Message();
            Console.WriteLine("ConcreteDecoratorA进行了Message方法的动态添加");
        }
    }
    public class ConcreteDecoratorB : Decorator
    {
        public override void Operation()
        {
            m_compontent.Operation();
            Console.WriteLine("ConcreteDecoratorB进行了方法的装饰");
        }
        public override void Message()
        {
            m_compontent.Message();
            Console.WriteLine("ConcreteDecoratorB进行了Message方法的动态添加");
        }
    }
    public class ConcreteDecoratorC : Decorator
    {
        public override void Operation()
        {
            m_compontent.Operation();
            Console.WriteLine("ConcreteDecoratorC进行了方法的装饰");
        }
        public override void Message()
        {
            m_compontent.Message();
            Console.WriteLine("ConcreteDecoratorC进行了Message方法的动态添加");
        }
    }
}

 

装饰者模式的基本代码原型差不多就这样子的。当我看到装饰者模式是这样的一个代码结构的时候,其实说心里话我难受。里面不是带着继承吗?为什么要继承,心理面不忍发了点牢骚。ConcreteConpontent是被装饰者对象,首先我们要确定要扩展的对象是可以让我们扩展的。其实我知道继承是为了拿到要扩展对象的行为,并且标示所有的装饰者是属于一种类型的,在使用的时候就可以用基类来使用所有的装饰者。如果没有继承显然是不能用基类进行统一调用的,继承还有一个作用就是为了拿到被装饰者的行为,用它的为操作不同的实例,是够聪明的。

3:

我假如我不需要用基类进行统一调用装饰者,我是否就可以不继承自被装饰者了;为了能够实现装饰者的无限递增的装饰,我对代码进行了简单的修改,请看代码:

using System;

namespace ConsoleApplication1
{
    public class ConcreteConpontent
    {
        public virtual void Operation()
        {
            Console.WriteLine("顶级待装饰对象");
        }
        public virtual void message()
        {
            Console.WriteLine("顶级对象消息");
        }
    }

    public abstract class Decorator
    {
        private ConcreteConpontent m_compontent;
        protected Decorator decorator;
        public void SetCompontent(ConcreteConpontent com, Decorator de)
        {
            m_compontent = com;
            decorator = de;
        }
        public void SetCompontent(ConcreteConpontent com)
        {
            m_compontent = com;
        }
        public virtual void Operation()
        {
            if (decorator != null)
                decorator.Operation();
            else
                m_compontent.Operation();
        }
        public virtual void message()
        {
            if (decorator != null)
                decorator.message();
            else
                m_compontent.message();
        }
    }
    public class ConcreteDecoratorA : Decorator
    {
        public override void Operation()
        {
            base.Operation();
            Console.WriteLine("ConcreteDecoratorA进行了方法的装饰");
        }
        public override void message()
        {
            base.message();
            Console.WriteLine("ConcreteDecoratorA进行了message方法的动态添加");
        }
    }

    public class ConcreteDecoratorB : Decorator
    {
        public override void Operation()
        {
            base.Operation();
            Console.WriteLine("ConcreteDecoratorB进行了方法的装饰");
        }
        public override void message()
        {
            base.message();
            Console.WriteLine("ConcreteDecoratorB进行了message方法的动态添加");
        }
    }
    public class ConcreteDecoratorC : Decorator
    {
        public override void Operation()
        {
            base.Operation();
            Console.WriteLine("ConcreteDecoratorC进行了方法的装饰");
        }
        public override void message()
        {
            base.message();
            Console.WriteLine("ConcreteDecoratorC进行了message方法的动态添加");
        }
    }
}

 如果我们这是想扩展一个简单的小功能,让我们继承一个很大的对象是不是有点不划算。只是想用被装饰者的行为,去操作装饰者原型实例。我们可以牺牲一下代码的冗余来解决这个性能问题。书上对继承的解释是用来避免手动输入被装饰者的行为代码。我觉得这点根本没有说服力。不继承我一样可以有同样的行为、一样可以实现无限递增的嵌套装饰者实例。要想实例套实例,那么他们必须来自同一个祖先,同样是装饰者,要想让装饰者套装饰者,那么在装饰者的类中需要有一个对装饰者类型的引用,但是每一个装饰者不可能一样。所以必须让他们继承同一个基类才行,后面再多的装饰者只要继承同一个基类那么就可以互相引用。[王清培版权所有,转载请给出署名]

总结:在我们选择使用装饰者模式的时候,需要根据自己的使用情况进行适当修改。在没有必要的情况下不需要继承那么大的一个对象。

 

posted @ 2011-07-24 16:44  王清培  阅读(1466)  评论(0编辑  收藏  举报