看过好多对装饰模式的讲解,他们几乎都有一句相同的话:对现有类功能的扩展。不知道大家怎么理解这句话的,之前我把”对功能的扩展“理解成”加功能=加方法“,比如Person类本来有两个功能:Eat 和 Run ,使用装饰模式后,可以再加一个功能:Sleep,这显然是不能的。增加Sleep意味着修改接口,装饰模式的功能并不是这样,那是怎样的呢?

还拿Person类来说明,比如现在有个需求:在吃饭前要洗手。 ”洗手“这个功能就是对Eat功能的扩展,添加“洗手”这个功能可以通过装饰模式添加,又比如吃完后,“男人要刷锅刷碗”, “刷锅刷碗”这个功能要添加给男人身上,也可以通过装饰模式动态给男人扩展这个功能,这个功能何时调用呢,当然是在吃饭的时候了,也就是调用Eat的时候,所以这些代码要写到Eat方法里。

再举个汽车的例子:

IMachine 接口是机器的接口,包含:Start()和Stop()两个功能。Car是IMachine的一个实现,SUVCar是Car的一个实现;

类:

     /// <summary>
/// 机器
/// </summary>
interface IMachine
{
void Start();
void Stop();
}

IMachine

     /// <summary>
/// 汽车
/// </summary>
abstract class Car : IMachine
{ public abstract void Start(); public abstract void Stop();
} /// <summary>
/// suv汽车
/// </summary>
class SUVCar : Car
{
public override void Start()
{
Console.WriteLine("我是SUV,发动机启动");
} public override void Stop()
{
Console.WriteLine("我是SUV,发动机熄火");
}
}

Car 和 SUVCar

这样的话,在Program里直接调用:

     class Program
{
static void Main(string[] args)
{
Console.WriteLine("****汽车的功能****");
IMachine car = new SUVCar(); //SUV汽车的功能
ControlMachine(car); Console.WriteLine("");
Console.ReadLine();
} static void ControlMachine(IMachine m)
{
m.Start();
Console.WriteLine("机器在运转.....");
m.Stop();
}
}

没问题,但是如果有新的需求时,比如:当汽车发动机启动时自动打开大灯,发动机熄火时关闭大灯,这如何实现呢?

可以用一下两种方式:1、继承的方式,添加一个能自动管理大灯的SUVCar,继承自Car,重写Start和Stop方法,然后Main中的IMachine car = new SUVCar(); 改成IMachine car = new LightSUVCar();即可。

2、装饰模式实现,原理就是 添加 控制灯光功能类,这个控制灯光的功能对汽车而言是个装饰,汽车装饰上了这个功能,就具有了这个功能。如何装饰呢?这个灯光控制的功能就像个带灯光控制功能的汽车盒子,它能容纳一个汽车,也具有汽车的所有功能,只是这些功能室通过调用汽车的功能来实现的,同时添加自己的功能。

好,那我们先定义一个可以容纳汽车的盒子(装饰类):

    class LightCarDecotar
{
private IMachine mac = null; public LightCarDecotar(IMachine c)
{
mac = c;
}
}

这个类可以通过构造函数来容纳一个机器(IMachine),当然也就可以容纳汽车了。构造函数的参数IMachine可以修改成Car,这要看你调用地方的接口是如何使用的。好,能够容纳后,还需要让这个盒子拥有汽车的功能,如何拥有呢,那就是让它继承接口:IMachine。由于汽车继承了IMachine,所以它继承了这个接口就拥有了相关功能:

    /// <summary>
/// 汽车启动时自动开启远光灯,熄火后自动关闭远光灯
/// </summary>
class LightCarDecotar : IMachine
{
private IMachine mac = null;
public LightCarDecotar(IMachine c)
{
mac = c;
} public void Start()
{
Console.WriteLine("车灯打开");
mac.Start();
} public void Stop()
{
mac.Stop();
Console.WriteLine("车灯关闭");
}
}

到这里,这个汽车车灯控制的装饰类搞定了,在Main中调用:

    class Program
{
static void Main(string[] args)
{
Console.WriteLine("****汽车的功能****");
IMachine car = new SUVCar(); //SUV汽车的功能
ControlMachine(car); Console.WriteLine(""); Console.WriteLine("****为汽车添加灯光功能****");
IMachine lightCar = new LightCarDecotar(car); //为汽车添加灯光功能
ControlMachine(lightCar); Console.WriteLine(""); Console.ReadLine();
} static void ControlMachine(IMachine m)
{
m.Start();
Console.WriteLine("机器在运转.....");
m.Stop();
}
}

由于装饰类:LightCarDecotar需要容纳一个汽车,所以要通过构造函数把汽车传递进去,由因为它继承自IMachine接口,故可以直接传递给ControlMachine方法的参数。运行结果:

同样的,给汽车再加一个”鸣笛“功能,鸣笛装饰类:

    /// <summary>
/// 汽车启动时自动鸣笛,关闭时也自动鸣笛
/// </summary>
class VoiceCarDecorator : IMachine
{
private IMachine mac = null;
public VoiceCarDecorator(IMachine c) { mac = c; } public void Start()
{
Console.WriteLine("喇叭鸣笛");
mac.Start();
} public void Stop()
{
mac.Stop();
Console.WriteLine("喇叭鸣笛");
}
}

调用的方式同上。

这是汽车就用了两个功能的装饰类了,再想一下,可能还会有这样的需求:汽车启动时即”开灯“又”鸣笛“,这怎么办呢?两种:1,再加一个装饰类,类中同时写”鸣笛“和”开灯“的代码。不过第一种方法貌似会出现重复的代码(鸣笛和开灯),这时就体现出装饰模式的强大之处和构思巧妙了。由于它能容纳一个汽车,而它自己就是汽车(因为继承了IMachine),所以它能容纳同类(装饰类)。

对于即“开灯”又“鸣笛”的汽车,可以这样写:

    IMachine voiceCar = new VoiceCarDecorator(car); //为汽车添加鸣笛功能
IMachine lightVoiceCar = new LightCarDecotar(voiceCar); //为汽车添加鸣笛和灯光功能
ControlMachine(lightVoiceCar);

先创建一个能鸣笛的车,然后创建一个能开灯的车,并把能鸣笛的车传递进去,装饰完的车就既可以鸣笛又可以开灯了。运行结果:

综上所述,您看出装饰模式的优势没?

例子中的类比较少,假设Car的子类有10种,其中的5种要加鸣笛,2种加开灯,3种加“既鸣笛又开灯”,如果用继承方式来实现,则要至少要加10个类通过重写方法来实现。但是如果通过装饰模式实现,则只需要加两个类(两个功能装饰类),然后在调用的时候按需装饰,装饰出来的对象就具有了装饰的功能。

以上例子是自己构想的,解释若有不确之处还请指出。谢谢

对装饰模式(Decorator)的解读的更多相关文章

  1. 装饰模式/decorator模式/结构型模式

    装饰模式Decorator 定义 为对象动态的增加新的功能,实现要求装饰对象和被装饰对象实现同一接口或抽象类,装饰对象持有被装饰对象的实例. java实现要点 定义一个接口或抽象类,作为被装饰者的抽象 ...

  2. 二十四种设计模式:装饰模式(Decorator Pattern)

    装饰模式(Decorator Pattern) 介绍动态地给一个对象添加一些额外的职责.就扩展功能而言,它比生成子类方式更为灵活.示例有一个Message实体类,某个对象对它的操作有Insert()和 ...

  3. 乐在其中设计模式(C#) - 装饰模式(Decorator Pattern)

    原文:乐在其中设计模式(C#) - 装饰模式(Decorator Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 装饰模式(Decorator Pattern) 作者:weba ...

  4. 设计模式 装饰模式(Decorator)

    设计模式 装饰模式(Decorator) @author ixenos 装饰模式是什么 1.装饰模式以对客户端透明的方式对象的功能,是继承关系的一个替代方案,但装饰模式可以在不创造更多子类的情况下,对 ...

  5. 设计模式-装饰模式(Decorator Pattern)

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

  6. Netty学习-IO体系架构系统回顾 & 装饰模式Decorator的具体使用

    Netty学习-IO体系架构系统回顾 IO和NIO的学习 NIO - 1.4 开始出的 在网络应用框架中,NIO得到了大量的使用,特别是netty里面 前提:对IO及其了解 对IO的总结和回顾 理解J ...

  7. 设计模式-09装饰模式(Decorator Pattern)

    1.模式动机 一般有两种方式可以实现给一个类或对象增加行为: 继承机制:使用继承机制是给现有类添加功能的一种有效途径,通过继承一个现有类可以使得子类在拥有自身方法的同时还拥有父类的方法.但是这种方法是 ...

  8. 设计模式系列之装饰模式(Decorator Pattern)——扩展系统功能

    说明:设计模式系列文章是读刘伟所著<设计模式的艺术之道(软件开发人员内功修炼之道)>一书的阅读笔记.个人感觉这本书讲的不错,有兴趣推荐读一读.详细内容也可以看看此书作者的博客https:/ ...

  9. 装饰模式 - Decorator 和 外观模式 - Facade

    装饰模式 Decorator,不改变接口但动态给对象加入责任,所需功能按顺序串联起来控制,比生成子类灵活. 外观模式 Facade,让接口更简单.为子系统中的一组接口提供一个一致的界面. 参考:

随机推荐

  1. [NOIP2005]采药

    2005年NOIP全国联赛普及组 [题目描述 Description] 辰辰是个天资聪颖的孩子,他的梦想是成为世界上最伟大的医师.为此,他想拜附近最有威望的医师为师.医师为了判断他的资质,给他出了一个 ...

  2. JSP页面同时操作所有Input输入框

    项目里要写个function,对页面上所有input输入框进行非空判断,对非空input全部置为readOnly,提交的时候判断是否有空白项目. var inputs=document.getElem ...

  3. poj 1696 Space Ant(模拟+叉积)

    Space Ant Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 3840   Accepted: 2397 Descrip ...

  4. usaco 安慰奶牛

    Description 约翰有N个牧场,编号依次为1到N.每个牧场里住着一头奶牛.连接这些牧场的有P条 道路,每条道路都是双向的.第j条道路连接的是牧场Sj和Ej,通行需要Lj的时间.两牧场之 间最多 ...

  5. php 链接access数据库

    php链接access数据库代码 <?php $odbc = "Driver={Microsoft Access Driver (*.mdb)};Dbq=".realpath ...

  6. css3 -&gt; 多栏布局

    在进行多栏布局时.使用bootstrap的栅格系统能够非常轻松的实现效果,事实上css3本身也提供了多兰布局的功能. 比方,我们在一个section标签内填充了非常多内容.同一时候希望内容可以显示成三 ...

  7. MP算法和OMP算法及其思想

    主要介绍MP(Matching Pursuits)算法和OMP(Orthogonal Matching Pursuit)算法[1],这两个算法尽管在90年代初就提出来了,但作为经典的算法,国内文献(可 ...

  8. WCF学习心得--客户端获取服务端自定义类数据

    因项目需求,需要一个WCF服务,赶鸭子上架吧!下面直接切入正题! 首先创建WCF应用程序,具体如何创建就不赘述了,网上一大篇,我主要说说自己遇到的问题 问题一:超时问题,在最后获取数据的时候突然提示服 ...

  9. JAVA IO之管道流总结大全(转)

    要在文本框中显示控制台输出,我们必须用某种方法“截取”控制台流.换句话说,我们要有一种高效地读取写入到System.out和 System.err 所有内容的方法.如果你熟悉Java的管道流Piped ...

  10. xshell十大技巧

    xshell是我用过的最好用的ssh客户端工具,没有之一.这个软件完全免费,简单易用,可以满足通过ssh管理linux vps所有需要,唯一遗憾的是没有官方中文版. 警告:不要下载所谓的汉化版,可能有 ...