1.装饰者模式介绍

  装饰者顾名思义就是对一个类添加一些额外的装饰(功能)。我们想给一个对象添加一些额外的功能又不改变对象内方法的签名怎么做呢?最常用的方法就是继承了,子类继承父类,然后重写父类的方法。考虑一种情况,如我们要给父类中的Show方法添加三个新功能功能a、功能b、功能c,这三种功能组合在一起时数目和执行顺序不同,效果也是不同的,为了现实所有的功能,我们需要创建很多子类,如子类1的show方法:BaseShow+功能a,子类2的show方法:BaseShow+ab,子类3的show方法:BaseShow+abc,子类4的show方法:BaseShow+ba.....子类n的show方法:BaseShow+功能cba(BaseShow指的是父类原本的show方法),如果添加的功能组合太多使用继承会造成子类爆炸。装饰器模式可以很好地解决这个问题。

  我们以大话设计模式中的人挑选服饰的例子来介绍装饰者模式的用法:小菜想通过各种服饰来打扮自己,服饰多种多样的,小菜可以自由组合,他可以穿西服+领带+皮鞋,也可以穿网鞋+T恤。

  先看一下装饰者模式的四种角色:抽象组件,具体组件,抽象装饰类,具体装饰类。我们在代码中看这个几个角色的作用。

AbstractPerson抽象类,抽象组件角色,定义了我们需要扩展的Show方法:

    /// <summary>
/// 抽象人类
/// </summary>
public abstract class AbstractPerson
{
//展示装饰方法,我们使用装饰器模式的目的就是为了扩展这个接口的功能
public abstract void Show();
}

Person类,具体组件角色,具体组件中的Show方法实现了原始的功能:

   /// <summary>
/// 人类 具体组件角色
/// </summary>
public class Person:AbstractPerson
{
public string Name { get; set; }
//待添加功能的Show方法,具体组件中的Show方法只有原始功能
public override void Show()
{
Console.Write($"打扮的人是{this.Name}:");
}
}

抽象装饰(Finery)类,抽象装饰角色。注意:这里的服饰并不指的是衣服,而是穿了用某种衣服装饰的人,理解这一点是理解装饰者模式的前提:

    //因为我们装饰后的person要直接替换装饰前的person,所以必须继承AbstractPerson
public abstract class Finery: AbstractPerson
{
protected AbstractPerson person;
//设置要打扮的人
public void SetPerson(AbstractPerson p)
{
this.person = p;
}
public override void Show()
{
if (person!=null)
{
person.Show();
}
}
}

具体服饰类,具体装饰角色,具体装饰角色通过重写Show方法来添加新功能:

   //t恤
public class TShirt : Finery
{
public override void Show()
{
base.Show();
Console.Write("大t恤 ");
}
}
//网鞋
public class Sneaker : Finery
{
public override void Show()
{
base.Show();
Console.Write("网鞋 ");
} }
//西装
public class Suit : Finery
{
public override void Show()
{
base.Show();
Console.Write("西装 ");
}
}
//领带
public class Tie:Finery
{
public override void Show()
{
base.Show();
Console.Write("领带 ");
}
}
//皮鞋
public class Leather : Finery
{
public override void Show()
{
base.Show();
Console.Write("皮鞋 ");
}
}

客户端调用:

    class Program
{
static void Main(string[] args)
{
//首先要有打扮的人
AbstractPerson xc = new Person() { Name = "小菜" }; Console.WriteLine("第一种装饰-------------------");
Finery personWithsuit = new Suit();
Finery personWithtie = new Tie();
Finery personWithleather = new Leather();
//装饰过程
personWithsuit.SetPerson(xc);//给小菜穿上西服
personWithtie.SetPerson(personWithsuit);//给穿上西服的小菜带上领带
personWithleather.SetPerson(personWithtie);//给穿上西服带上领带的小菜穿上皮鞋
personWithleather.Show(); Console.WriteLine();
Console.WriteLine("第二种装饰-------------------");
Finery personWithTshirt = new TShirt();
Finery personWithSneaker = new Sneaker();
//装饰过程
personWithTshirt.SetPerson(xc);//给小菜穿上t恤
personWithSneaker.SetPerson(personWithTshirt);//给穿上t恤的小菜穿上网球鞋
personWithSneaker.Show(); Console.ReadKey();
}
}

运行程序结果:

2.小结

上边例子的类图:

装饰者模式的使用场景:

  当我们需要动态添加类的功能同时不改变类的结构时可以使用装饰者模式,装饰类本质是一个现有类的包装。

装饰者模式的优点:

  1.一个类需要添加一些功能,而这些功能按数目、顺序组合形成的效果不一样,如果用继承会造成子类过多,装饰者模式可以很好地解决这个问题;

  2.使用装饰者模式我们可以动态的添加/删除类的功能,灵活性好。

装饰者模式的缺点:

  多层装饰比较复杂,我们需要注意装饰顺序等因素。如先穿内裤再穿裤子,是正常人;而先穿裤子再穿内裤就是超人了。在开发中先过滤字符串再加密,和先加密字符串再过滤的效果是完全不同的。

补充:

装饰器模式和桥接模式都采用了组合大于继承的思想,不同的地方在于桥接模式中的组合用于is-a情景,如桥接模式的例子中蓝色的圆是一个几何图形,而装饰器模式中组合用于has-a情景,如人有一件衣服,人有一双鞋子。

C#设计模式(11)——装饰者模式的更多相关文章

  1. Java 设计模式泛谈&装饰者模式和单例模式

    设计模式(Design Pattern) 1.是一套被反复使用.多人知晓的,经过分类编目 的 代码设计经验总结.使用设计模式是为了可重用代码,让代码更容易维护以及扩展. 2.简单的讲:所谓模式就是得到 ...

  2. C#设计模式(9)——装饰者模式(Decorator Pattern)

    一.引言 在软件开发中,我们经常想要对一类对象添加不同的功能,例如要给手机添加贴膜,手机挂件,手机外壳等,如果此时利用继承来实现的话,就需要定义无数的类,如StickerPhone(贴膜是手机类).A ...

  3. 设计模式之装饰者模式-java实例

    设计模式之装饰者模式 需求场景 我们有了别人提供的产品,但是别人提供的产品对我们来说还不够完善,我们需要对这个产品的功能进行补强,此时可以考虑使用装饰者模式. 我们已经有了产品,而且这个产品的功能非常 ...

  4. Java设计模式 - - 单例模式 装饰者模式

    Java设计模式 单例模式 装饰者模式 作者 : Stanley 罗昊 [转载请注明出处和署名,谢谢!] 静态代理模式:https://www.cnblogs.com/StanleyBlogs/p/1 ...

  5. python 设计模式之装饰器模式 Decorator Pattern

    #写在前面 已经有一个礼拜多没写博客了,因为沉醉在了<妙味>这部小说里,里面讲的是一个厨师苏秒的故事.现实中大部分人不会有她的天分.我喜欢她的性格:总是想着去解决问题,好像从来没有怨天尤人 ...

  6. PHP设计模式之装饰器模式(Decorator)

    PHP设计模式之装饰器模式(Decorator) 装饰器模式 装饰器模式允许我们给一个类添加新的功能,而不改变其原有的结构.这种类型的类属于结构类,它是作为现有的类的一个包装 装饰器模式的应用场景 当 ...

  7. 实践GoF的23种设计模式:装饰者模式

    摘要:装饰者模式通过组合的方式,提供了能够动态地给对象/模块扩展新功能的能力.理论上,只要没有限制,它可以一直把功能叠加下去,具有很高的灵活性. 本文分享自华为云社区<[Go实现]实践GoF的2 ...

  8. 再起航,我的学习笔记之JavaScript设计模式13(装饰者模式)

    装饰者模式 装饰者模式(Decorator): 在不改变原对象的基础上,通过对其进行过包装拓展(添加属性高或者方法)使原有对象可以满足用户的更复杂需求. 如果现在我们有个需求,需要做一个提交表单,当我 ...

  9. Java 的设计模式之一装饰者模式

    刚开始接触装饰者的设计模式,感觉挺难理解的,不够后来花了一个晚上的时间,终于有头绪了 装饰者设计模式:如果想对已经存在的对象进行装饰,那么就定义一个类,在类中对已经有的对象进行功能的增强或添加另外的行 ...

  10. Head First设计模式之装饰者模式(Decorator Pattern)

    前言: 本节将深度讨论继承滥用问题,将会学到使用对象组合的方式,在运行时装饰类,在不修改任何底层代码的情况下,给对象赋予新的职责. 1.    基本需求:咖啡连锁店业务扩张需要重新设计订单系统 背景: ...

随机推荐

  1. 洛谷P1550打井

    打井 题目 该题是一个最小生成树的好题,但是比起一般的最小生成树来说他不仅仅有各个井相连,而且还要和地下水相连,所以地下水我们也可以看成一口井. 代码 #include <bits/stdc++ ...

  2. HDU2204 Eddy's爱好

    题意:给你一个正整数N,确定在1到N之间有多少个可以表示成M^K(K>1)的数. 解析:一个数N 开K次根后得到M  则小于M的所有数的K次方一定小于N 因为任何一个合数都能分解为素数的乘积 所 ...

  3. npm 淘宝源

    --------- npm: 淘宝源设置:npm config set registry https://registry.npm.taobao.org

  4. Hdoj 2084.数塔 题解

    Problem Description 在讲述DP算法的时候,一个经典的例子就是数塔问题,它是这样描述的: 有如下所示的数塔,要求从顶层走到底层,若每一步只能走到相邻的结点,则经过的结点的数字之和最大 ...

  5. iis express添加虚拟目录

    在调试WEB时,还是使用IIS EXPRESS比较方便, 在IIS中,选择网站,右击,添加虚拟目录或者应用程序,就能添加虚拟目录了.. 在IIS EXPRESS中,添加虚拟目录如下 1.右击IIS E ...

  6. js日期格式转换的相关问题探讨

    探讨问题1: 如何将 2017年8月22日 转换成 2017-8-22 / 2017-08-22呢 '2017年8月22日'.replace(/[年月日]/g,'-'); '2017年8月22日'.m ...

  7. day27

    27.01 反射(类的加载概述和加载时机) 1.类的加载 当程序要使用某个类时,如果该类还未加载到内存中,系统会通知加载,连接,初始化三步来实现对这个类初始化 a.加载 是指将.class文件读入内存 ...

  8. centos7搭建ELK Cluster集群日志分析平台(四):Fliebeat-简单测试

    续之前安装好的ELK集群 各主机:es-1 ~ es-3 :192.168.1.21/22/23 logstash: 192.168.1.24 kibana: 192.168.1.25 测试机:cli ...

  9. Zabbix使用netstat监控会话

    原文链接 TCP的连接状态对于我们web服务器来说是至关重要的,尤其是并发量ESTAB:或者是syn_recv值,假如这个值比较大的话我们可以认为是不是受到了攻击,或是是time_wait值比较高的话 ...

  10. CentOS6.5安装JDK1.8

    1.查看Linux自带的JDK是否已安装(如果安装则卸载CentOS已安装的低版本) 安装好的CentOS会自带OpenJdk,用命令 java -version,会有下面的信息: java -ver ...