首先来看一个例子:
比如,饮料可以分为很多种类,而这里我取一个咖啡,那么这个咖啡呢,有多种形式的,
比如有加糖了的咖啡,有加奶的咖啡,也有加热了的咖啡,也有加了冰块的咖啡。
而各个顾客的选择却是不同的,比如,有的客户是要加糖的咖啡,而有的客户却是要加冰的咖啡,
也就是需求是各种各样的,那么如何实现这种情况呢?
先来看一种愚笨的做法,那就是你可以通过继承来实现,

虽然上面的做法确实可以提供加糖加冰的咖啡,但是,这种方法也太拙劣了吧,
如果我要加糖和加热的咖啡呢?如果我还有更多的需求呢?
如果我新增饮料巧克力奶茶,然后其中也可以加糖,加奶,加热,加冰呢?
如果使用上面的方式来完成上面提到的种种需求的话?
My God !!!
其实从上面的例子中反映出来的问题是,
确实可以通过继承来实现扩展(比如,由咖啡扩展成了加了糖的咖啡),
但是并不一定说使用继承就可以达到弹性设计。
为了解决上面出现的问题,一种新的设计模式应运而生,那就是装饰者模式。
装饰者模式动态的给一个对象添加一些责任(也就是功能),若要扩展功能的话,
装饰者提供了比继承更有弹性的替代方案,因为装饰者模式比生成子类更加灵活。

下面就来解释装饰者模式了
装饰者模式呢,其实可以看做是一种在已有功能上动态添加新的功能的一种方式,
在不用装饰者模式的前提下,如果要在已有的功能上添加新功能,一般都是可以使用继承的,
但是,继承的缺点呢,在上面的咖啡的例子中也暴露的很明显,同时,使用继承的话,
添加功能不是动态的,因为子类完全继承了父类,
而使用装饰者模式的话,您可以在客户端按照需求一个一个的包装对象,
通过包装对象来添加新功能,
这样便实现了动态添加新功能,
比如,我可以对 Component 通过 ConcreteDecoratorA 来包装一个 State 状态,
或者是通过 ConcreteDecoratorB 来包装一个新的行为(功能)Behavior ,
这样便实现了功能的动态添加。
又比如上面的咖啡的例子,就可以使用装饰者模式来实现,我先是对咖啡使用加糖来包装,
这样就可以得到加糖的咖啡,而后再使用冰来包装加了糖的咖啡,这样就可以得到加了糖,
并且加了冰的咖啡。
其实光这样说是感受不到多少装饰者模式带来的优点的
下面就将上面提到的咖啡这个例子写出来看看吧,这样理解起来便清晰多了

先来看 Drink 类
using System; 
namespace Decorator 

    public abstract class Drink 
    { 
        ///
<summary> 
        /// 在抽象类中只定义了一个抽象接口 
        /// 然后可以通过这个抽象接口来给对象动态的添加功能 
        /// </summary> 
        public abstract void ShowDrink(); 
    } 
}
然后就是一个 Coffee 类
using System; 
namespace Decorator 

    public class Coffee
: Drink 
    { 
        private string name; 
    
   public Coffee(string name) 
        { 
            this.name = name; 
        } 
        ///
<summary> 
        /// 这里呢,也可以给当前的对象添加一些功能 
        /// 比如这里就是指定了咖啡的名称 
        /// 不过在这里添加的功能是静态添加的 
        /// </summary> 
        public override void ShowDrink() 
        { 
            Console.WriteLine("咖啡名称为:{0}    ",
this.name); 
        } 
    } 
}
下面再来看 DecoratorDrink 类
namespace Decorator 

    public class DecoratorDrink
: Drink 
    { 
        ///
<summary> 
        /// 在装饰类中必须要保存一个对于对象的引用 
        /// 其是继承自 Drink 这个抽象类 
        /// 它是从外类来扩展
Drink 类 
        /// 所以 Drink 类并不知道 DecoratorDrink 类的存在 
        /// </summary> 
        protected Drink drink; 
    
   public DecoratorDrink(Drink drink) 
        { 
            this.drink = drink; 
        } 
    
   public override
void ShowDrink() 
    
   { 
            if (drink != null) 
            { 
                //必须执行父类的 ShowDrink 
                //其主要是通过多态来实现的,因为 Coffee 也是 Drink 类型 
                drink.ShowDrink(); 
            } 
        } 
    } 
}
还有就是装饰类 Sugar
using System; 
namespace Decorator 

    public class Sugar :
DecoratorDrink 
    { 
        ///
<summary> 
        /// 必须要有所要扩展的对象 
        /// 比如扩展咖啡的话,必须要存在咖啡这个对象 
        /// 同时,这里直接调用了父类的构造函数 
        /// </summary> 
        /// <param
name="drink"></param> 
        public
Sugar(Drink drink) 
            : base(drink) 
        { 
    
   } 
    
   public override
void ShowDrink() 
    
   { 
           //首先必须要调用父类的 ShowDrink 
            base.ShowDrink(); 
            //然后下面就可以添加新功能了 
            Console.WriteLine("加糖   "); 
        } 
    } 
}
装饰类 Milk
using System; 
namespace Decorator 

    public class Milk :
DecoratorDrink 
    { 
        public Milk(Drink drink) 
            : base(drink) 
        { 
    
   } 
    
   public override void ShowDrink() 
        { 
            base.ShowDrink(); 
           //添加新功能 
            Console.WriteLine("加奶   "); 
        } 
    } 
}
装饰类 Ice
using System; 
namespace Decorator 

    public class Ice : DecoratorDrink 
    { 
        public Ice(Drink drink) 
            : base(drink) 
        { 
    
   } 
        public override void ShowDrink() 
        { 
            base.ShowDrink(); 
            //添加新功能 
            Console.WriteLine("加冰   "); 
        } 
    } 
}
装饰类 Hot
using System; 
namespace Decorator 

    public class Hot : DecoratorDrink 
    { 
        public Hot(Drink drink) 
            : base(drink) 
        { 
    
   } 
    
   public override void ShowDrink() 
        { 
           base.ShowDrink(); 
       
    //添加新功能 
            Console.WriteLine("加热   "); 
        } 
    } 
}
最后就是 Main 函数了
using System; 
using Decorator
namespace DecoratorTest 

    class Program 
    { 
        static void Main(string[] args) 
        { 
            Coffee coffee =
new Coffee("咖啡一号"); 
            //给咖啡加糖,也就是使用糖来装饰咖啡 
            Sugar sugar
= new Sugar(coffee); 
       
    //给加了糖的咖啡加热,也就是使用加热来装饰咖啡 
            Hot hot = new Hot(sugar); 
            //显示出当前咖啡的状态 
            hot.ShowDrink(); 
       
    Console.WriteLine(); 
       
    coffee = new Coffee("咖啡二号"); 
            sugar = new
Sugar(coffee); 
            //给加了糖的咖啡加奶 
            Milk milk = new Milk(sugar); 
            //给加了糖和奶的咖啡加冰块 
            Ice ice = new Ice(milk); 
            ice.ShowDrink(); 
       
    Console.ReadLine(); 
        } 
    } 
}
最后当然是要看一下效果咯
 
从 Main 函数中可以看出,我可以方便的通过将各个装饰类组合起来(一个个的新功能添加起来)而成为新产品,
上面呢,就是装饰者模式的一个最基本的应用和介绍了,
其实,装饰者模式呢,它把类中的一些装饰功能移除,再将这些装饰功能写到另外的类中
这样可以简化核心类的复杂度,同时,面对不同的需求时,可以提供代码得复用,
否则,你要完成需求“咖啡加糖”的话,就得写一个咖啡加糖类,再变点需求又得变一大堆,
通过装饰模式,可以有效的将类的核心功能和装饰功能分离开来,比如上面的 Demo 的核心功能是咖啡,
而装饰功能就是加糖,加奶,加热,加冰这些了,
同时,通过装饰者模式,你可以很好的扩展自己的设计
比如,上面的 Demo ,如果在后面再来需求,说可以加盐(应该不会有这种需求吧?哈哈哈),
那么你只需再完成一个加盐的装饰类,然后再在客户端动态添加加盐这项新功能就可以了,
而上面提到的这些,用继承几乎上无法避免违背开闭原则。
同时,在这里还必须提一下的就是,装饰模式的装饰顺序很重要
在上面的 Demo 中无法体现出装饰模式装饰顺序的重要性,
再来看一个装饰的例子,以用来体现出装饰模式装饰顺序的重要,
那就是一个人,它穿衣服,其实是可以用装饰模式来解决的,
因为你可以把内衣,外衣,内裤,外裤,鞋子等等内容都看做一个个的装饰类,
那么这里,装饰顺序就显得比较重要了,
比如,如果你先装饰了外裤,然后再装饰内裤,那就麻烦大了,
因为你变成了超人---典型的内裤外穿~~~~~
从这里可以看出装饰顺序还是很重要的!!!
上面提到的都是装饰模式的优点,而事实上,任何事物都是两面的,
有利必有弊,装饰模式也一样的,
那就是使用装饰模式,会使整个的设计当中出现很多的小类,也就是许许多多的装饰类
比如,上面的关于咖啡的 Demo 中就出现了 4 个小的装饰类,
如果,一个设计中,装饰模式过度使用的话,会平添很多的小类,
那样的话,会让程序变得更加复杂
关于装饰模式呢,就谈到这里了~~~

装饰者模式(Decorator)的更多相关文章

  1. 浅谈设计模式--装饰者模式(Decorator Pattern)

    挖了设计模式这个坑,得继续填上.继续设计模式之路.这次讨论的模式,是 装饰者模式(Decorator Pattern) 装饰者模式,有时也叫包装者(Wrapper),主要用于静态或动态地为一个特定的对 ...

  2. 【PHP设计模式 09_ZhuangShiQi.php】装饰器模式 (decorator)

    <?php /** * [装饰器模式 (decorator)] * 有时候发布一篇文章需要经过很多人手,层层处理 */ header("Content-type: text/html; ...

  3. 设计模式(八)装饰器模式Decorator(结构型)

    设计模式(八)装饰器模式Decorator(结构型) 1. 概述 若你从事过面向对象开发,实现给一个类或对象增加行为,使用继承机制,这是所有面向对象语言的一个基本特性.如果已经存在的一个类缺少某些方法 ...

  4. 设计模式 - 装饰者模式(Decorator Pattern) Java的IO类 用法

    装饰者模式(Decorator Pattern) Java的IO类 用法 本文地址: http://blog.csdn.net/caroline_wendy/article/details/26716 ...

  5. 设计模式 - 装饰者模式(Decorator Pattern) 具体解释

    装饰者模式(Decorator Pattern) 具体解释 本文地址: http://blog.csdn.net/caroline_wendy/article/details/26707033 装饰者 ...

  6. 装饰器模式-Decorator(Java实现)

    装饰器模式-Decorator(Java实现) 装饰器模式允许向一个现有的对象添加新的功能, 同时又不改变其结构. 其中 "现有对象"在本文中是StringDisplay类. 添加 ...

  7. 装饰者模式 Decorator

    项目:咖啡计费系统 背景:现有系统中有一个抽象类Beverage,有2个抽象方法GetDescription和Cost. namespace DecoratorPattern { /// <su ...

  8. 设计模式学习--装饰者模式(Decorator Pattern)

    概念: 装饰者模式(Decorator Pattern): 动态地将功能添加到对象,相比生成子类更灵活,更富有弹性. 解决方案: 装饰者模式的重点是对象的类型,装饰者对象必须有着相同的接口,也也就是有 ...

  9. 大话设计模式--装饰者模式 Decorator -- C++实现实例

    1.装饰者模式 Decorator 动态地给一个对象添加一个额外的职责, 就添加功能来说, 装饰模式比生成子类更为灵活. 每个装饰对象的实现和如何使用这个对象分离,  每个装饰对象只关心自己的功能,不 ...

  10. 设计模式(三):“花瓶+鲜花”中的装饰者模式(Decorator Pattern)

    在前两篇博客中详细的介绍了"策略模式"和“观察者模式”,今天我们就通过花瓶与鲜花的例子来类比一下“装饰模式”(Decorator Pattern).在“装饰模式”中很好的提现了开放 ...

随机推荐

  1. java学习面向对象之封装

    在以往几节当中我们讲到了什么是类,类就是对一类事物的描述,比如现在我们有一个人类 class Person { /** *这里我们分别在name和age上加上了元素的访问权限 *这里的private是 ...

  2. C Looooops(扩展欧几里得求模线性方程)

    http://poj.org/problem?id=2115 题意:对于C的循环(for i = A; i != B; i+=C)问在k位存储系统内循环多少次结束: 若循环有限次能结束输出次数,否则输 ...

  3. [转]Android DPAD not enabled in AVD

     转自:http://blog.csdn.net/flyhigh200703/article/details/8955484 问题描述:打开Android的仿真器,右侧的按键部分对于上下左右键出现以下 ...

  4. 开源代码搜索器searchcode

    项目主页:https://searchcode.com/ 查看API:https://searchcode.com/api/ 关于:https://searchcode.com/about/ Sear ...

  5. 数据结构(线段树):BZOJ 1103 [POI2007]大都市meg

    1103: [POI2007]大都市meg Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 1791  Solved: 925[Submit][Stat ...

  6. excel时会弹出向程序发送命令时出现问题的提示框

    出现此问题需要做两个操作来解决: 1.在开始所有程序中找到Microsoft Excel 2007的运行程序,右键选择属性,在兼容性标签将“以管理员身份运行此程序”的勾去掉. 2.在打开的Excel程 ...

  7. Fire Net(深搜 和一前不一样的深搜)

    /* http://acm.tzc.edu.cn/acmhome/problemdetail.do?&method=showdetail&id=1162 本题妙处: 用一个数对行取商是 ...

  8. POJ 2912 Rochambeau

    题意:有一些人玩石头剪刀布,其中有一个人(称其为裁判)可以出“石头”,“剪刀”,“布”中的任意一个,其他人永远只能出相同的一个.即有的人只能出剪刀,有的人只能出石头,有的人只能出布.进行了多次对决,每 ...

  9. poj2318 水题(二分+叉积)

    题目链接:http://poj.org/problem?id=2318 #include<cstdio> #include<cstring> #include<cmath ...

  10. SQLServer2005 常用语法大全

    SQL分类: DDL—数据定义语言(CREATE,ALTER,DROP,DECLARE) DML—数据操纵语言(SELECT,DELETE,UPDATE,INSERT) DCL—数据控制语言(GRAN ...