• 设计模式之装饰模式


    装饰模式(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方法即可。如果要换装扮,也很简单,只需定义需要的衣服类型,并且进行装饰即可完成,代码是不是非常的低耦合呢。

    后记总结:

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

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

  • 相关阅读:
    我所遭遇过的游戏中间件---HumanIK
    我所遭遇过的游戏中间件--Kynapse
    3D屏保:排色榜
    3维DEMO: 抽奖圆盘
    MySQL存储过程中的3种循环
    MyISAM与InnoDB两者之间区别与选择,详细总结,性能对比
    如何执行字符串的PHP代码
    PHP 注册错误和异常处理机制
    Mysql表中唯一编号的分配机制
    装系统w7、ubuntu、centos等系统(一)
  • 原文地址:https://www.cnblogs.com/ListenFly/p/3220992.html
Copyright © 2020-2023  润新知