设计模式之装饰模式

装饰模式(Decorator):动态地给一个对象添加一些额外的职责,就增加功能来说,装饰模式比生成子类更为灵活。

上图为装饰模式的结构图,Component定义一个对象接口可以给这些对象动态地添加职责。ConcreteComponent是定义了一个具体的对象,也可以给这个对象添加一些职责(ConcreteComponent主要就是作为一个具体的对象存在)。Decorator,装饰抽象类,继承自Component,从外类扩展Component类的功能,相对于Component来说无需知道Decorator存在。ConcreteDecorator就是具体的装饰对象,起到给Component添加职责的功能。

P.S:如果只有一个ConcreteComponent而没有抽象的Component类,那么Decorator类可以是ConcreteComponent的一个子类。同样道理,如果只有一个ConcreteDector类(即只有一个具体的装饰类),那么就没必要单独建立一个Decorator类,可以把Decorator和ConcreteDecorator的职责合并。

从上图中可以看到装饰模式的四要素:

1.装饰的接口即Component;

2.装饰的具体对象ConcreteComponent,用于实现添加职责的功能;

3.抽象的装饰类,同时继承自Component;

4.具体的装饰类,继承自抽象的装饰类。

 Component:

  abstract class Component
    {
         public abstract void Operation();
    }

ConcreteComponent:

    class ConcreteComponent:Component
    {
        public override void Operation()
        {
            Console.WriteLine("具体具体操作");
        }
    }

Decorator抽象装饰类:

 abstract class Decorator : Component
    {
        protected Component component;

        public Decorator()
        {
        }

        /// <summary>
        /// 设置Component
        /// </summary>
        /// <param name="component"></param>
        public void SetComponent(Component component)
        {
            this.component = component;
        }

        /// <summary>
        /// 重写Operation方法,实际执行的是Component的Operation
        /// </summary>
        public override void Operation()
        {
            if (component != null)
            {
                component.Operation();
            }
        }
    }

 具体装饰类:

    class ConcreteDecoratorA:Decorator
    {
        public override void Operation()
        {
            //先执行基类的Operation
            base.Operation();
            Console.WriteLine("具体装饰类A的操作");
        }
    }

    class ConcreteDecoratorB : Decorator
    {
        public override void Operation()
        {
            //先执行基类的Operation
            base.Operation();
            Console.WriteLine("具体装饰类B的操作");
        }
    }

    class ConcreteDecoratorC : Decorator
    {
        public override void Operation()
        {
            //先执行基类的Operation
            base.Operation();
            Console.WriteLine("具体装饰类C的操作");
        }
    }

 调用方法:

            ConcreteComponent component = new ConcreteComponent();
            ConcreteDecoratorA c1 = new ConcreteDecoratorA();
            ConcreteDecoratorB c2 = new ConcreteDecoratorB();

            c1.SetComponent(component);
            c2.SetComponent(c1);
            c2.Operation();

调用效果如下:

装饰的过程:先定义了具体的Component类ConcreteComponent,然后使用ConcreteDecoratorA 的实例化对象c1来包装component,然后用ConcreteDecoratorB的对象c1来包装c1,最终执行c2的Operation方法。其实装饰模式最主要的是使用SetComponent来对对象进行包装的。这样每个装饰对象的实例就和如何使用这个对象分离开了,每个装饰对象只关心如何被添加到对象链当中。

整个过程是层层传递的,最终会先执行被传递的那个Component对象(也可以说是具体的装饰对象),整个的过程主要通过SetComponent进行完成,以及在具体对象的Operation中执行base的操作(这样才可以执行到传递的Component的行为,其实就是一个继承的作用)。

下面举例一个穿衣服的装饰模式例子:

场景:衣服有很多种,T恤,裤子,西装,运动鞋,皮鞋,领带等,至于怎么组合无需关心,交给客户决定。
分析:衣服要有人来穿,所以人是一个具体的Component,上述的各种衣服最终还是一个衣服,所以一个衣服的积累,作为抽象的装饰存在,另外各种衣服就是一个个具体的装饰对象。

人(Person具体的Component):

  class Person
    {
        public Person() { }
        //当前人
        private string name;
        public Person(string name)
        {
            this.name = name;
        }
        /// <summary>
        /// 展示衣服
        /// </summary>
        public virtual void Show()
        {
            Console.WriteLine(string.Format("装扮的{0}", name));
        }
    }

衣服(服饰的基类):

 /// <summary>
    /// 衣服类
    /// </summary>
    class Finery:Person
    {
        protected Person component;

        /// <summary>
        /// 设置打扮的衣服
        /// </summary>
        /// <param name="component"></param>
        public void Decorate(Person component)
        {
            this.component = component;
        }
        public override void Show()
        {
            if (component!=null)
            {
                component.Show();
            }
        }
    }

其他具体的服饰类:

    /// <summary>
    /// T恤
    /// </summary>
    class TShirt:Finery
    {
        public override void Show()
        {
            base.Show();
            Console.WriteLine("T恤");
        }
    }

    /// <summary>
    /// 裤子
    /// </summary>
    class Trouser:Finery
    {
        public override void Show()
        {
            base.Show();
            Console.WriteLine("裤子");
        }
    }

    /// <summary>
    /// 运动鞋
    /// </summary>
    class SportShoes:Finery
    {
        public override void Show()
        {
            base.Show();
            Console.WriteLine("运动鞋");
        }
    }

    /// <summary>
    /// 西装
    /// </summary>
    class Suit:Finery
    {
        public override void Show()
        {
            base.Show();
            Console.WriteLine("西装");
        }
    }

    /// <summary>
    /// 皮鞋
    /// </summary>
    class EatherShoes:Finery
    {
        public override void Show()
        {
            base.Show();
            Console.WriteLine("皮鞋");
        }
    }

    /// <summary>
    /// 领带
    /// </summary>
    class Tie:Finery
    {
        public override void Show()
        {
            base.Show();
            Console.WriteLine("领带");
        }
    }

 调用:

       Console.WriteLine("第一种打扮:");
            Person person = new Person("Blue");
            TShirt shirt = new TShirt();
            Trouser trouser = new Trouser();
            SportShoes sportShoes = new SportShoes();

            //开始装饰了
            shirt.Decorate(person);
            trouser.Decorate(shirt);
            sportShoes.Decorate(trouser);
            //开始展示衣服了
            sportShoes.Show();

            Console.WriteLine();

            Console.WriteLine("第二种打扮:");
            Suit suit = new Suit();
            EatherShoes eatherShoes = new EatherShoes();
            Tie tie = new Tie();

            //再次装饰了
            suit.Decorate(person);
            eatherShoes.Decorate(suit);
            tie.Decorate(eatherShoes);
            //开始展示衣服了
            tie.Show();

代码中一共展示了两种不同的装扮,除了实例化的衣服不同之外,其余过程均相同。实例化一个Person类,即实例化一个具体的Component,然后开始实例化各种各样的衣服,然后通过Decorate方法进行装饰,最后调用Show进行衣服的展示,效果如下:

 现在如果想增加一种衣服怎么做呢,很简单,增加一个衣服类,继承自Finery类,重写Show方法即可。如果要换装扮,也很简单,只需定义需要的衣服类型,并且进行装饰即可完成,代码是不是非常的低耦合呢。

后记总结:

 装饰模式是为已有功能动态地添加更多功能的一种方式。当系统需要新功能时,装饰模式提供了一个很好的方案,它把每个要装饰的功能放在了单独的类中,并让这个类包装它所需要的对象,因此当需要执行特殊行为时,客户代码就可以在运行时有选择地使用装饰功能包装对象。
优点:把类的核心职责和装饰功能区分开了,而且去除相关类中重复的装饰逻辑。

 

好了,此次模式到此结束,欢迎大家多提意见和建议。

 

posted @ 2013-07-28 21:17  wangyafei_it  阅读(237)  评论(0编辑  收藏  举报