首页 > 设计模式 > 初尝Decorator 模式

初尝Decorator 模式

一副画,可以挂在墙上。但通常,它们都会被装入相框之后,再被挂起来。据说如此一来,可以保证画面持久如新。如果这样一幅画的名字叫做《蒙娜丽莎的微笑》,那么在相框之外,可能还隔着一道水晶墙。据说如此一来,不但画面可以持久如新,还能保证名画本身不受到“意外”的损伤。在软件系统中,有时候我们会使用继承来扩展对象的功能,但是由于继承为类型引入的静态特质(编译固定),使得这种扩展方式缺乏灵活性;并且随着子类的增多(扩展功能的增多),各种子类的组合(扩展功能的组合)会导致更多子类的膨胀。为什么不使用前面蒙娜丽莎的智慧来解决“子类复子类,子类何其多”的困境呢?这就是我今天刚学的Decorator 模式

意图

动态地给一个对象增加一些额外的职责。就增加功能而言,Decorator模式比生成子类更为灵活。

结构图

Decorator设计模式 初尝Decorator 模式

假设要对现有文档进行功能的扩充,比如加密、压缩等。即可使用Decorator 模式进行,下面便是代码了:

using System;

namespace Decorator
{
    abstract class Document {
        private string name;
        public string Name
        {
            get { return name; }
            set { name = value; }
        }

       //public abstract void Open();
       //public abstract void Close();
       public abstract void Save();
    }

    class EncryptDecorator : Document {
        private Document doc;
        public EncryptDecorator(Document doc) {
            this.doc = doc;
            base.Name = doc.Name;
        }
        private void Encrypt() {
            Console.WriteLine("{0} has been Encypted!",doc.Name);
        }
        //先加密,然后保存
        public override void Save() {
            this.Encrypt();
            doc.Save();
        }

    }

    class ZIPDecorator : Document {
        private Document doc;
        public ZIPDecorator(Document doc) {
            this.doc = doc;
            base.Name = doc.Name;
        }
        private void ZIP() {
            Console.WriteLine("{0} has been Ziped!",doc.Name);
        }
        //先保存,然后压缩
        public override void Save() {
            doc.Save();
            this.ZIP();
        }
    }

    class PDF : Document{
        public PDF(){
            base.Name = "PDF";
        }
        public override void Save(){
            Console.WriteLine("{0} has been Saved!", base.Name);
        }
    }

    class TXT : Document {
        public TXT() {
            base.Name = "TXT";
        }
        public override void Save() {
            Console.WriteLine("{0} has been Saved!",base.Name);
        }

    }

    class Program
    {
        static void Main(string[] args)
        {
            Document doc = new TXT();
            Console.WriteLine("普通的TXT 文档:");
            doc.Save();
            Console.WriteLine("-------------------------------");
            EncryptDecorator doc1 = new EncryptDecorator(doc);
            Console.WriteLine("仅扩展了加密功能的TXT文档:");
            doc1.Save();
            Console.WriteLine("-------------------------------");
            //仅扩展了压缩功能
            ZIPDecorator doc2 = new ZIPDecorator(doc);
            Console.WriteLine("仅扩展了压缩功能的TXT文档:");
            doc2.Save();
            Console.WriteLine("-------------------------------");
            //既扩展了加密功能,又扩展了压缩功能
            ZIPDecorator doc3 = new ZIPDecorator(doc1);
            Console.WriteLine("既扩展了加密功能,又扩展了压缩功能的TXT文档:");
            doc3.Save();
        }
    }
}

运行截图

Decorator 运行截图

总结:

  • Decorator 是一个非常有用的模式,经常用来对一些现有类进行包装。通过采用组合、而非继承的手法,Decorator模式实现了在运行时动态地扩展对象功能的能力,而且可以根据需要扩展多个功能。避免了单独使用继承带来的“灵活性差”和“多子类衍生问题”。
  • Decorator类在接口上表现为is-a Component的继承关系,即Decorator类继承了Component类所具有的接口。但在实现上又表现为has-a Component的组合关系,即Decorator类又使用了另外一个Component类。我们可以使用一个或者多个Decorator对象来“装饰”一个Component对象,且装饰后的对象仍然是一个Component对象。
  • Decortor模式并非解决“多子类衍生的多继承”问题,Decorator模式的应用要点在于解决“主体类在多个方向上的扩展功能”——是为“装饰”的含义。

另外,Decortor 和Bridge 模式之间是有着一定区别的:

Decorator是对已有功能的增强, 装饰类都是围绕被装饰类已有的功能而展开的, 无论装饰类怎么变, 它都必须围绕被装饰类来变化(或者是围绕二者公共的接口来变化), 因为对于客户程序来说, 调用装饰前后的对象应该是一致的. 而Bridge模式是将行为从被桥接对象(抽象类)中分离出去, 完全放到实现类中去实现, 行为实现将更少的受到被桥接对象的限制. 所以如果这种约束是必要的,就可以采用Decorator模式, 反之则可以采用Bridge模式 。

  1. 本文目前尚无任何评论.
  1. 2010年4月28日17:47 | #1