C#设计模式(11)——装饰者模式
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)——装饰者模式的更多相关文章
- Java 设计模式泛谈&装饰者模式和单例模式
设计模式(Design Pattern) 1.是一套被反复使用.多人知晓的,经过分类编目 的 代码设计经验总结.使用设计模式是为了可重用代码,让代码更容易维护以及扩展. 2.简单的讲:所谓模式就是得到 ...
- C#设计模式(9)——装饰者模式(Decorator Pattern)
一.引言 在软件开发中,我们经常想要对一类对象添加不同的功能,例如要给手机添加贴膜,手机挂件,手机外壳等,如果此时利用继承来实现的话,就需要定义无数的类,如StickerPhone(贴膜是手机类).A ...
- 设计模式之装饰者模式-java实例
设计模式之装饰者模式 需求场景 我们有了别人提供的产品,但是别人提供的产品对我们来说还不够完善,我们需要对这个产品的功能进行补强,此时可以考虑使用装饰者模式. 我们已经有了产品,而且这个产品的功能非常 ...
- Java设计模式 - - 单例模式 装饰者模式
Java设计模式 单例模式 装饰者模式 作者 : Stanley 罗昊 [转载请注明出处和署名,谢谢!] 静态代理模式:https://www.cnblogs.com/StanleyBlogs/p/1 ...
- python 设计模式之装饰器模式 Decorator Pattern
#写在前面 已经有一个礼拜多没写博客了,因为沉醉在了<妙味>这部小说里,里面讲的是一个厨师苏秒的故事.现实中大部分人不会有她的天分.我喜欢她的性格:总是想着去解决问题,好像从来没有怨天尤人 ...
- PHP设计模式之装饰器模式(Decorator)
PHP设计模式之装饰器模式(Decorator) 装饰器模式 装饰器模式允许我们给一个类添加新的功能,而不改变其原有的结构.这种类型的类属于结构类,它是作为现有的类的一个包装 装饰器模式的应用场景 当 ...
- 实践GoF的23种设计模式:装饰者模式
摘要:装饰者模式通过组合的方式,提供了能够动态地给对象/模块扩展新功能的能力.理论上,只要没有限制,它可以一直把功能叠加下去,具有很高的灵活性. 本文分享自华为云社区<[Go实现]实践GoF的2 ...
- 再起航,我的学习笔记之JavaScript设计模式13(装饰者模式)
装饰者模式 装饰者模式(Decorator): 在不改变原对象的基础上,通过对其进行过包装拓展(添加属性高或者方法)使原有对象可以满足用户的更复杂需求. 如果现在我们有个需求,需要做一个提交表单,当我 ...
- Java 的设计模式之一装饰者模式
刚开始接触装饰者的设计模式,感觉挺难理解的,不够后来花了一个晚上的时间,终于有头绪了 装饰者设计模式:如果想对已经存在的对象进行装饰,那么就定义一个类,在类中对已经有的对象进行功能的增强或添加另外的行 ...
- Head First设计模式之装饰者模式(Decorator Pattern)
前言: 本节将深度讨论继承滥用问题,将会学到使用对象组合的方式,在运行时装饰类,在不修改任何底层代码的情况下,给对象赋予新的职责. 1. 基本需求:咖啡连锁店业务扩张需要重新设计订单系统 背景: ...
随机推荐
- P1008 三连击
题目背景 本题为提交答案题,您可以写程序或手算在本机上算出答案后,直接提交答案文本,也可提交答案生成程序. 题目描述 将1,2,⋯,9共9个数分成3组,分别组成3个三位数,且使这33个三位数构成1:2 ...
- HDU5745-La Vie en rose-字符串dp+bitset优化
这题现场的数据出水了,暴力就能搞过. 标解是拿bitset做,转移的时候用bitset优化过的操作(与或非移位)来搞,复杂度O(N*M/w) w是字长 第一份标程的思路很清晰,然而后来会T. /*-- ...
- 轮询、长轮询、websock
引入 Web端即时通讯技术:即时通讯技术简单的说就是实现这样一种功能:服务器端可以即时地将数据的更新或变化反应到客户端,例如消息即时推送等功能都是通过这种技术实现的.但是在Web中,由于浏览器的限制, ...
- Python中xlwt解析
1.导入模块 import xlwt 2.构造excel表 workbook = xlwt.Workbook() #返回一个工作簿对象 3.构造sheet w ...
- X问题 HDU - 1573(excrt入门题)
X问题 Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submiss ...
- PhantomJS报错warnings.warn('Selenium support for PhantomJS has been deprecated, please use headless '
原因:Selenuim已经放弃PhantomJS3.x了,建议使用火狐或者谷歌无头浏览器. 解决方法: 1.phantomjs降级,换个2.x版本的 2.使用无头浏览器,示例代码(自己改了改,如有错误 ...
- Hdoj 2018.母牛的故事 题解
Problem Description 有一头母牛,它每年年初生一头小母牛.每头小母牛从第四个年头开始,每年年初也生一头小母牛.请编程实现在第n年的时候,共有多少头母牛? Input 输入数据由多个测 ...
- can物理信号-----------显性和隐性
can信号使用差分电压传送,两条信号线被称为CAN_H和CAN_L.静态时均是2.5v左右,此时状态表示为逻辑“1”,也可以叫做隐性.用CAN_H比CAN_L高表示逻辑“0”,称为显性,此时通常电压值 ...
- 洛谷P1731 生日蛋糕
李煜东太神了啊啊啊啊啊! 生日蛋糕,著名搜索神题(还有虫食算). 当年的我30分.... 这哥们的程序0ms... 还有他的树网的核也巨TM神. 疯狂剪枝! DFS(int d, int s, int ...
- [luogu4860][Roy&October之取石子II]
题目链接 思路 这个题和上个题类似,仔细推一下就知道这个题是判断是否是4的倍数 代码 #include<cstdio> #include<iostream> #define f ...