无废话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");

        }

    }

}

时间: 2024-10-30 12:56:11

无废话C#设计模式之十三:Decorator的相关文章

无废话C#设计模式之二十二:总结(针对GOF23)

本文配套源码 比较 设计模式 常用程度 适用层次 引入时机 结构复杂度 Abstract Factory 比较常用 应用级 设计时 比较复杂 Builder 一般 代码级 编码时 一般 Factory Method 很常用 代码级 编码时 简单 Prototype 不太常用 应用级 编码时.重构时 比较简单 Singleton 很常用 代码级.应用级 设计时.编码时 简单 Adapter 一般 代码级 重构时 一般 Bridge 一般 代码级 设计时.编码时 一般 Composite 比较常用

无废话C#设计模式之五:Prototype

意图 用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象. 场景 游戏场景中的有很多相似的敌人,它们的技能都一样,但是随着敌人出现的位置不同,这些人的能力不太一样.假设,我们现在需要把三个步兵组成一队,其中还有一个精英步兵,能力特别高.那么,你或许可以创建一个敌人抽象类,然后对于不同能力的步兵创建不同的子类.然后,使用工厂方法等设计模式让调用方依赖敌人抽象类. 问题来了,如果有无数种能力不同步兵,难道需要创建无数子类吗?还有,步兵模型的初始化工作是非常耗时的,创建这么多步兵对象可能还

无废话C#设计模式之一:开篇

什么是设计模式? 什么是少林拳呢?少林拳是少林僧人经过长期的总结,得出的一套武功套路.有一本叫做少林拳法的武功秘籍,上面记载这这套拳法的适用人群,打法套路和学成后的效果.设计模式虽然记录在了设计模式一书上,但是要真正掌握设计模式光靠看每一个模式的结构并且进行模仿是不够的.试想一下,在真枪实战的情况下,谁会和你按照少林拳法,一二三四的套路打呢?打套路也只能用来看看,只有当你能根据不同的场景灵活出招的时候才能说是学会了这套拳法.相似的例子还有三十六计,这也是一种模式,每种计谋都是针对不同场景的,如果

无废话C#设计模式之十四:Template Method

意图 定义一个操作中的算法的骨架,而将一些步骤延迟到子类中.Template Method使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤. 场景 模版方法是非常容易理解的设计模式,一来是因为它没有过多结构上的交错,二来是因为这种代码复用技术对于掌握OO知识的人来说非常容易可以想到,很可能你已经在很多地方运用了模版方法.在运用一些设计模式的时候常常也会一起运用模版方法,甚至有的设计模式本身就带有模版方法的思想. 今天,我们给出这样一个实际的例子.做过银行支付.支付宝支付的人都知道,

无废话C#设计模式之八:Facade

意图 为子系统中的一组接口提供一个一致的界面,Facade模式定义了一个高层接口,这个接口使得这一子系统更加容易使用. 场景 在一个为游戏充值的网站中,创建订单需要与三个外部接口打交道: l 用户系统:根据用户名获取用户ID.查看用户是否已经激活了游戏 l 卡系统:查看某种类型的充值卡是否还有库存 l 充值系统:创建一个订单,并且返回订单号 如果直接让网站和三个外部接口发生耦合,那么网站因为外部系统接口修改而修改的概率就很大了,并且就这些小接口来说并不是十分友善,它们提供的大多数是工具方法,具体

无废话C#设计模式之七:Adapter

意图 把一个类的接口变换成客户端所期待的另一种接口,从而使原本接口不匹配而无法在一起工作的两个类能够在一起工作. 场景 假设网络游戏的客户端程序分两部分.一部分是和服务端通讯的大厅部分,大厅部分提供的功能有道具购买.读取房间列表.创建房间以及启动游戏程序.另一部分就是游戏程序了,游戏程序和大厅程序虽然属于一个客户端,但是由不同的公司在进行开发.游戏大厅通过实现约定的接口和游戏程序进行通讯. 一开始的设计就是,大厅程序是基于接口方式调用游戏程序启动游戏场景方法的.在大厅程序开发接近完成的时候,公司

无废话C#设计模式之六:Builder

意图 将一个复杂的构建与其表示相分离,使得同样的构建过程可以创建不同的表示. 场景 在电脑城装机总有这样的经历.我们到了店里,先会有一个销售人员来询问你希望装的机器是怎么样的配置,他会给你一些建议,最终会形成一张装机单.和客户确定了装机配置以后,他会把这张单字交给提货的人,由他来准备这些配件,准备完成后交给装机技术人员.技术人员会把这些配件装成一个整机交给客户. 不管是什么电脑,它总是由CPU.内存.主板.硬盘以及显卡等部件构成的,并且装机的过程总是固定的: l 把主板固定在机箱中 l 把CPU

无废话C#设计模式之四:Factory Method

意图 定义一个创建产品对象的工厂接口,将实际创建工作推迟到子类中. 场景 上次,我们使用抽象工厂解决了生产一组产品的问题,但是我们把各个场景作为了具体工厂来生产场景模式和场景纹理两个产品.在调用代码中也并没有出现具体工厂的影子.其实,场景类要做的不仅仅是创建具体的产品系列,可能它还需要做一个初始化工作.那么,我们就需要在调用代码中能得到这个场景类. 在前一节中,由于场景类(比如HalfPaper)本身是具体级别的(具体工厂).那么,我们也不应该在调用代码中直接依赖场景类.因此,我们可以使用工厂方

无废话C#设计模式之三:Abstract Factory

意图 提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类. 场景 还是上次说的那个网络游戏,定下来是一个休闲的FPS游戏.和CS差不多,8到16个玩家在游戏里面分成2组对战射击.现在要实现初始化场景的工作.要呈现一个三维物体一般两个元素是少不了的,一是这个物体的骨架,也就是模型,二就是这个骨架上填充的纹理. 我们知道,这样的一个游戏不可能只有一张地图,而且地图的数量肯定是会一直增加的.如果游戏在初始化场景的时候需要根据不同的地图分别加载模型和纹理对象,那么势必就会使得场景的扩充变