• (原创)无废话C#设计模式之十三:Decorator


     

    无废话C#设计模式之十三:Decorator

     

    意图

     

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

     

    场景

     

    在设计网络游戏的武器系统时,开始并没有考虑到武器的强化和磨损。之后,策划人员说希望给游戏增加强化系统和修理系统,那么我们的武器类型就需要对外提供强化、磨损、修理等方法了。发生这种改动是我们最不愿意看到的,按照设计原则,我们希望功能的扩展尽可能不要修改原来的程序。你可能会想到使用继承来实现,但是策划人员的需求是有的武器能磨损能修理,不能强化,有的武器能强化,但是不会磨损,有的武器既能强化还能磨损和修理。遇到这样的情况,继承的方案可能不适合了,一来继承的层次可能会很多,二来子类的数量可能会很多。

    由此,引入装饰模式来解决这个问题。装饰模式使得我们能灵活赋予类额外的职责,并且使得设计和继承相比更合理。

     

    示例代码

     

    using System;

    using System.Collections.Generic;

    using System.Text;

     

    namespace DecoratorExample

    {

        class Program

        {

            static void Main(string[] args)

            {

                Weapon w = new Rifle();

                w.ShowInfo();

                Enhance enhancedWeapon = new Enhance(w);

                enhancedWeapon.EnhanceAmmo();

                enhancedWeapon.ShowInfo();

                Wear wornWeapon = new Wear(w);

                wornWeapon.WearByRate(0.8);

                wornWeapon.ShowInfo();

            }

        }

     

        abstract class Weapon

        {

            private double ammo;

     

            public double Ammo

            {

                get { return ammo; }

                set { ammo = value; }

            }

     

            private double attack;

     

            public double Attack

            {

                get { return attack; }

                set { attack = value; }

            }

     

            private double speed;

     

            public double Speed

            {

                get { return speed; }

                set { speed = value; }

            }

     

            private string name;

     

            public string Name

            {

                get { return name; }

                set { name = value; }

            }

     

            public abstract void ShowInfo();

        }

     

        class Rifle : Weapon

        {

            public Rifle()

            {

                this.Ammo = 100;

                this.Attack = 10;

                this.Speed = 5;

                this.Name = "Rifle";

            }

     

            public override void ShowInfo()

            {

                Console.WriteLine(string.Format("ammo\t{0}", Ammo));

                Console.WriteLine(string.Format("attack\t{0}", Attack));

                Console.WriteLine(string.Format("speed\t{0}", Speed));

                Console.WriteLine(string.Format("name\t{0}",  Name));

            }

        }

     

        abstract class Decorator : Weapon

        {

            protected Weapon w;

     

            public Decorator(Weapon w)

            {

                this.w = w;

            }

     

            public override void ShowInfo()

            {

                w.ShowInfo();

            }

        }

     

        class Enhance : Decorator

        {

            public Enhance(Weapon w) : base(w) { }

     

            public void EnhanceAmmo()

            {

                w.Ammo += 20;

                Console.WriteLine(">>>>>>>>>>>>Enhanced");

            }

        }

     

        class Wear : Decorator

        {

            public Wear(Weapon w) : base(w) { }

     

            public void WearByRate(double rate)

            {

                w.Speed = w.Speed * rate;

                w.Attack = w.Attack * rate;

                Console.WriteLine(">>>>>>>>>>>>Worn");

            }

        }

    }

     

    代码执行结果如下图:

     

     

    代码说明

     

    l         Weapon是抽象构件角色。

    l         Rifle是具体构件角色,实现抽象构件的接口。

    l         Decorator是装饰角色。装饰角色有两个特点,一是继承了抽象构件的接口,二是有一个构件角色的实例。

    l         EnhanceWear是具体装饰角色,它们负责给构件附加责任。

    l         客户端在使用装饰角色的时候并没有针对抽象构件进行编程,因为我们确实需要使用具体装饰角色提供的额外方法,这种类型的装饰叫做半透明装饰。

     

    何时采用

     

    l         从代码角度来说,如果你觉得由于功能的交叉扩展不会导致非常多的子类或者非常多的继承层次的话可以考虑装饰模式。

    l         从应用角度来说,如果你希望动态给类赋予或撤销一些职责,并且可以任意排列组合这些职责的话可以使用装饰模式。

     

    实现要点

     

    l         让装饰角色还继承抽象构件角色也是装饰模式最大的特点,目的就是给抽象构件增加职责,对外表现为装饰后的构件。

    l         让装饰角色拥有构件角色实例的目的就是让构件能被多个装饰对象来装饰。

    l         在具体应用中可以灵活一点,不一定要有抽象构件和装饰角色。但是,装饰对象继承装饰对象并且拥有它实例的两大特点需要体现。

    l         透明装饰一般通过在基类方法前后进行扩充实现,半透明装饰一般通过新的接口实现。

     

    注意事项

     

    l         装饰模式和桥接模式的区别是,前者是针对功能的扩展,本质上还是一样东西,而后者针对多维护变化。装饰模式的思想在于扩展接口而桥接模式的思想是分离接口。

    l         装饰类可能会比较琐碎,并且不利于复用,装饰模式在增加了灵活性的同时也降低了封装度,在实际应用中可以和其它模式配合。

    欢迎大家阅读我的极客时间专栏《Java业务开发常见错误100例》【全面避坑+最佳实践=健壮代码】
  • 相关阅读:
    “零接触”新需求,如何快速实现体温检测数字化管控方案?
    AR公共安全及应急指挥中的应用 | TVP思享
    当模板方法遇到了委托函数,你的代码又可以精简了
    为什么要用内插字符串代替string.format
    如何让多个不同类型的后端网站用一个nginx进行反向代理实际场景分析
    8天入门docker系列 —— 第八天 让程序跑在swarm集群上
    8天入门docker系列 —— 第七天 让你的container实现跨主机访问
    8天入门docker系列 —— 第六天 搭建自己的私有镜像仓库Registry
    8天入门docker系列 —— 第五天 使用aspnetcore小案例熟悉容器互联和docker-compose一键部署
    8天入门docker系列 —— 第四天 使用aspnetcore小案例熟悉端口映射和挂载目录
  • 原文地址:https://www.cnblogs.com/lovecherry/p/922182.html
Copyright © 2020-2023  润新知