• 02.09 装饰模式


    设计模式——装饰模式

    需求

    从一个编程任务说起。有段旧代码如下:

            public class Girl

            {

                public virtual void GoSchool() { Console.Write("女孩去上学!"); }

            }

    客户提出了新的要求,随着时代的进步,现代女孩上学还需要增加新的功能,有带个花花帽子,穿个漂亮裙子,画眉涂口红等可选功能,但是旧类不允许修改,因为旧的功能还是适合那些传统女孩,还在那些情况下有用。总结就是:不修改旧类代码的情况下,需要增加新的功能;这些新增的功能还可以任意组合。下面先尝试用继承机制来实现。

    继承旧类来实现添加功能:女孩戴个花花帽子

            public class GirlCap : Girl

            {

                public override void GoSchool()

                {

                    Console.WriteLine("女孩戴个花花帽子;");

                    base.GoSchool();

                }

            }

           

    继承旧类来实现添加功能:女孩穿个漂亮裙子

            public class GirlSkirt : Girl

            {

                public override void GoSchool()

                {

                    Console.WriteLine("女孩穿个漂亮裙子;");

                    base.GoSchool();

                }

            }

    前面两个单独的功能都实现了,戴帽子与穿裙子的组合功能也是可以实现的,      

            public class GirlCapSkirt : GirlSkirt

            {

                public override void GoSchool()

                {

                    Console.WriteLine("女孩戴个花花帽子;");

                    base.GoSchool();

                }

            }

    但是到这里我们可以发现,如果还有其它的单独功能可以用单独的子类来实现,但是他们的各种组合就比较麻烦。更糟糕的是,随着各项需要新增功能的增多,还需要增加很多单独功能子类及所有可能组合功能的子类。就是说这种需求使用继承来解决将会陷入非常复杂的情况。装饰模式(Decorator Pattern)就是解决这种问题的。

    定义

    装饰模式是在不必改变原类文件和使用继承的情况下,动态的扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象。若要扩展功能,装饰提供了比继承更具弹性的代替方案。

    意图:动态地给一个对象添加一些额外的职责。

    实现方法:装饰模式使用被装饰类的一个子类的实例,在客户端将这个子类的实例委托给装饰类来,从而获得额外的功能。

      

    装饰模式由4部分组成:(1)抽象的被装饰者(Abstract Component),定义被装饰着规格;(2)具体的被装饰者(Concrete Component),实现抽象被装饰者;(3)抽象的装饰类(Decorator),引用被装饰者一个子类的实例,原搬被装饰者的功能,为各子类添加额外功能提供基类;(4)具体的装饰类(Concrete Decorator),继承/实现抽象的装饰类,在重定义方法里增加一项单独的装饰功能。

    案例

        class Program

        {

            // 抽象的装饰目标

            public interface IGirl { void GoSchool();}

            // 具体的装饰目标

            public class Girl : IGirl

            {

                public virtual void GoSchool() { Console.WriteLine("女孩去上学!"); }

            }

            // 抽象装饰类

            public class GirlDecorator : IGirl

            {

                public GirlDecorator(IGirl girl) { this._Girl = girl; }

                private IGirl _Girl;    // 内部引用一个需要装饰的兑现实例

                public virtual void GoSchool() { this._Girl.GoSchool(); }

            }

            // 具体装饰类:女孩戴个花花帽子

            public class GirlCapDecorator : GirlDecorator

            {

                public GirlCapDecorator(IGirl girl) : base(girl) { }

                public override void GoSchool()

                {

                    Console.WriteLine("女孩戴个花花帽子;");

                    base.GoSchool();

                }

            }

            // 具体装饰类:女孩穿个漂亮裙子

            public class GirlSkirtDecorator : GirlDecorator

            {

                public GirlSkirtDecorator(IGirl girl) : base(girl) { }

                public override void GoSchool()

                {

                    Console.WriteLine("女孩穿个漂亮裙子;");

                    base.GoSchool();

                }

            }

            // 具体装饰类:女孩穿个漂亮长裤

            public class GirlTrousersDecorator : GirlDecorator

            {

                public GirlTrousersDecorator(IGirl girl) : base(girl) { }

                public override void GoSchool()

                {

                    Console.WriteLine("女孩穿个漂亮长裤;");

                    base.GoSchool();

                }

            }

            static voidMain(string[] args)

            {

                // 客户程序

                // 女孩戴个花花帽子,穿着漂亮裙子去上学:

                IGirl girl1 = new GirlSkirtDecorator(new GirlCapDecorator(new Girl()));

                girl1.GoSchool();

                // 女孩戴个花花帽子,穿着漂亮长裤去上学:

                IGirl girl2 = new GirlTrousersDecorator(new GirlCapDecorator(new Girl()));

                girl2.GoSchool();

                // 女孩穿着漂亮裙子,穿着漂亮长裤去上学:这个逻辑比较荒唐,说明了装饰模式的缺点

                IGirl girl3 = new GirlSkirtDecorator(new GirlTrousersDecorator(new Girl()));

                girl3.GoSchool();

            }

        }

    优缺点

    优点:适用装饰模式,能够比使用继承关系更灵活的扩展对象的功能,它可以动态地增加对象的功能,并且可以随意组合这些功能。

    缺点:正是因为可以由客户端随意组合功能,就可能被客户组合出一些不合理的逻辑,就像上面案例中既穿裙子,又穿长裤的荒唐逻辑。

    适用场景

    在不修改原类的情况下,需要动态地给一个对象增加一些额外的功能,并且这些额外的功能还需要可以随意组合,就非常适合装饰模式了。可以说装饰模式解决了动态扩展对象功能的问题。

    补充

  • 相关阅读:
    mobileSelect学习
    使用qrcode生成二维码
    点点点右边有内容
    搜索框search
    input样式和修改
    art-template模板引擎高级使用
    Nodejs中的路径问题
    异步编程(回调函数,promise)
    在nodejs中操作数据库(MongoDB和MySQL为例)
    MongoDB数据库
  • 原文地址:https://www.cnblogs.com/sagahu/p/2714230.html
Copyright © 2020-2023  润新知