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. POJ 3621-Sightseeing Cows-最优比率环|SPFA+二分

    最优比率环问题.二分答案,对于每一个mid,把节点的happy值归类到边上. 对于每条边,用mid×weight减去happy值,如果不存在负环,说明还可以更大. /*---------------- ...

  2. CodeForces 589F-Gourmet and Banquet-二分答案

    有m盘菜,每盘有一个开始时间和结束时间,必须每盘都吃同样的时间.问最多能吃多久. 二分答案,然后用一个优先队列维护当前时间内的菜,然后每次都吃结束时间最小的那盘. #include <cstdi ...

  3. Android Studio 显示 logcat

    首先调出 logcat,在整个android studio的左下角(藏的好,尼玛.) 接着设置下面三个红框 1 选择你自己的模拟器. 2 选择Warm 3 选择not filter

  4. 三天STL与pbds(平板电视)

    19.02.11 ~ 19.02.13 hjmmm要专攻STL辣 先列一下大纲? 第一天:各种基础容器 第二天:实现平衡树和平板电视pbds 第三天:非变异算法和变异算法 那么我们就开始吧! Day1 ...

  5. Before NOIP 2018

    目录 总结 刷题 2018 - 9 - 24 2018 - 9 - 25 2018 - 9 - 26 2018 - 9 - 27 2018 - 9 - 28 2018 - 9 - 29 2018 - ...

  6. Python将是人工智能时代的最佳编程语言

    Python将是人工智能时代的最佳编程语言 移动互联网取代PC互联网领跑在互联网时代的最前沿,Android和iOS一度成为移动互联网应用平台的两大霸主,成为移动开发者首选的两门技术,HTML5以其跨 ...

  7. 用决策树(CART)解决iris分类问题

    首先先看Iris数据集 Sepal.Length--花萼长度 Sepal.Width--花萼宽度 Petal.Length--花瓣长度 Petal.Width--花瓣宽度 通过上述4中属性可以预测花卉 ...

  8. Ubuntu16.04下的NetCore环境搭建(附录含Ubuntu 18.04 安装 NetCore2.1)

    跨平台系列汇总:http://www.cnblogs.com/dunitian/p/4822808.html#linux VSCode安装:http://www.cnblogs.com/dunitia ...

  9. java 内存调试 mat

    https://www.ibm.com/developerworks/cn/opensource/os-cn-ecl-ma/ http://www.open-open.com/lib/view/ope ...

  10. 用tkinter制作签名设计窗口

    效果如下: from tkinter import * from tkinter import messagebox import requests import re from PIL import ...