c#装饰器模式详解
基础介绍:
动态地给一个对象添加一些额外的职责。适用于需要扩展一个类的功能,或给一个类添加多个变化的情况。
装饰器,顾名思义就是在原有基础上添加一些功能。
大家都只知道如果想单纯的给原有类增加一些功能,可以直接继续该类生成一个子类就可以。
举个例子,如果现在有个手机类,想给手机贴膜,传统的做法就是新建一个手机类的子类(手机贴膜子类),继承自手机类。
使用这个子类就可以完成对手机的贴膜操作。
那如果又想给手机按保护壳的话,传统做法有两种,可以继续新建一个手机类的子类(手机保护壳子类),继承自手机类。
使用这个子类可以给手机按保护壳,但也就失去了给手机贴膜的功能。另一种做法,新建一个手机贴膜类的子类(手机贴膜+保护壳),也就是手机类的子子类。
这样即可以贴膜也可以按手机壳。
大家思考一个问题,如果有很多个装饰并且想随意组合的话,那就有N个子类并且存在很深的继承链路。
想要解决这个问题,就可以用到装饰器了。
比如贴膜装饰、保护壳装饰、贴纸装饰等等,它们都是独立存在的,只继承自装饰器类。
什么意思呢?就是说给手机贴膜的时候它并不会给手机按保护壳的功能,职责单一,贴膜装饰器只负责给手机贴膜。
这样做有什么好处呢?好处就是这些装饰可以随意组合,比如即想贴膜又想按保护壳,就可以将贴膜装饰+保护壳装饰进组组合。
在装饰器模式中各个角色有:
- 抽象构件(Component)角色:规范手机的构成
- 具体构件(ConcreteComponent)角色:继承自抽象构件,具体实现手机。(大多情况下,可以省略抽象构件,抽象装饰类可以直接继承)
- 抽象装饰类(Decorator)角色:创建一个构件(Component)对象的实例,可以使用这个实例调用原构件的功能,并规范装饰类。
- 具体装饰类(ConcreteDecorator)角色:继承自抽象装饰类,具体实现该装饰功能。
应用场景:
原有类无法修改或者修改困难的情况下,对类进行多次扩展或功能性比较相互独立,有效防止多次扩展的情况下子类的膨胀。
注:如果类的扩展比较简单,并且不会多次进行扩展的情况下直接使用类的继承生成子类的方式更为方便快捷。
创建方式:
为了方便说明,以下实例就不创建抽象构件了。
首先先看下不使用装饰器进行类的扩展
1 /// <summary>
2 /// 手机类
3 /// </summary>
4 public class Phone
5 {
6 public void Print()
7 {
8 Console.WriteLine("手机");
9 }
10 }
11
12 /// <summary>
13 /// 手机贴膜
14 /// </summary>
15 public class Sticker : Phone
16 {
17 public Sticker()
18 {
19 base.Print();
20 }
21
22 /// <summary>
23 /// 进行贴膜
24 /// </summary>
25 public void AddSticker()
26 {
27 Console.WriteLine("给手机贴膜");
28 }
29 }
30
31 /// <summary>
32 /// 手机保护壳
33 /// </summary>
34 public class ProtectiveCase : Phone
35 {
36 public ProtectiveCase()
37 {
38 base.Print();
39 }
40
41 /// <summary>
42 /// 按保护壳
43 /// </summary>
44 public void AddProtectiveCase()
45 {
46 Console.WriteLine("给手机按保护壳");
47 }
48 }
49
50 /// <summary>
51 /// 即贴膜又按保护壳
52 /// </summary>
53 public class ProtectiveCaseAndSticker : Sticker
54 {
55 public ProtectiveCaseAndSticker()
56 {
57 }
58
59 /// <summary>
60 /// 按保护壳
61 /// </summary>
62 public void AddProtectiveCase()
63 {
64 Console.WriteLine("给手机按保护壳");
65 }
66 }
67
68 /// <summary>
69 /// 客户端
70 /// </summary>
71 class Client
72 {
73 static void Main(string[] args)
74 {
75 //创建一个手机
76 Phone phone = new Phone();
77 phone.Print();
78 Console.WriteLine("\r\n");
79
80 //给手机贴膜
81 Sticker sticker = new Sticker();
82 sticker.AddSticker();
83 Console.WriteLine("\r\n");
84
85 //给手机按保护壳
86 ProtectiveCase protectiveCase = new ProtectiveCase();
87 protectiveCase.AddProtectiveCase();
88 Console.WriteLine("\r\n");
89
90 //即贴膜又按保护壳
91 ProtectiveCaseAndSticker protectiveCaseAndSticker = new ProtectiveCaseAndSticker();
92 protectiveCaseAndSticker.AddSticker();
93 protectiveCaseAndSticker.AddProtectiveCase();
94 Console.ReadKey();
95 }
96 }通过上述实例可以看出,如果各个扩展功能比较独立的话可以直接进行继承扩展。
如果各个功能直接有交集的情况下,会造成很深的继承关系。
比如上述实例中,如果单独贴膜或者单独安装保护壳则直接继承手机类即可。
但如果想要即贴膜又要安装保护壳,各自继承手机类的方式就行不通了,只能在贴膜类或者保护壳类的基础上进行扩展。
如果还有添加手机挂饰,那就还需要再一层继承关系。
要解决这个问题就用到了装饰器,下面看看使用装饰器是怎么给手机添加新功能的。
使用装饰器模式对类进行扩展
1 /// <summary>
2 /// 手机类
3 /// </summary>
4 public class Phone
5 {
6 public void Print()
7 {
8 Console.WriteLine("手机");
9 }
10 }
11
12 /// <summary>
13 /// 装饰抽象类
14 /// </summary>
15 public abstract class Decorator : Phone
16 {
17 private Phone phone;
18
19 public Decorator(Phone p)
20 {
21 this.phone = p;
22 }
23
24 public abstract void AddDecorator();
25 }
26
27 /// <summary>
28 /// 贴膜装饰
29 /// </summary>
30 public class Sticker : Decorator
31 {
32 public Sticker(Phone p)
33 : base(p)
34 {
35 }
36
37 public override void AddDecorator()
38 {
39 Console.WriteLine("给手机贴膜");
40 }
41 }
42
43 /// <summary>
44 /// 保护壳装饰
45 /// </summary>
46 public class ProtectiveCase : Decorator
47 {
48 public ProtectiveCase(Phone p)
49 : base(p)
50 {
51 }
52
53 /// <summary>
54 /// 按保护壳
55 /// </summary>
56 public override void AddDecorator()
57 {
58 Console.WriteLine("给手机按保护壳");
59 }
60 }
61
62 /// <summary>
63 /// 客户端
64 /// </summary>
65 class Client
66 {
67 static void Main(string[] args)
68 {
69 //单独给手机贴膜
70 Phone phone = new Phone();
71 phone.Print();
72 Decorator sticker = new Sticker(phone);
73 sticker.AddDecorator();
74
75 //单独给手机按保护壳
76 phone = new Phone();
77 phone.Print();
78 Decorator protectiveCase = new ProtectiveCase(phone);
79 protectiveCase.AddDecorator();
80 Console.WriteLine("\r\n");
81
82 //即贴膜又按保护壳
83 phone = new Phone();
84 phone.Print();
85 //首先创建贴膜装饰实例,将手机对象传入
86 Decorator decorator = new Sticker(phone);
87 //进行贴膜操作
88 decorator.AddDecorator();
89 //创建保护壳装饰实例,将贴膜后的手机对象传入
90 decorator = new ProtectiveCase(decorator);
91 //进行按保护壳操作
92 decorator.AddDecorator();
93 Console.ReadKey();
94 }
95 }从上述实例中可以看出,各个装饰类只对装饰抽象类负责,职责单一。
各个装饰进行组合时,方便随意。新增装饰时,只需要新增一个继承自装饰抽象类的子类即可实现以原有装饰的随意组合使用。
总结:
想要扩展一个类的时候,传统的继承生成子类的形式,适用于扩展简单,并且不会多次扩展的情况下。
而如果一个类的扩展是周期性,多次扩展的或功能性比较相互独立的情况下,可以使用装饰器,可以有效的解决传统继承扩展子类膨胀的问题。
装饰模式是继承的一个替代模式,装饰模式可以动态扩展一个实现类的功能。
c#装饰器模式详解的更多相关文章
- (十)装饰器模式详解(与IO不解的情缘)
作者:zuoxiaolong8810(左潇龙),转载请注明出处,特别说明:本博文来自博主原博客,为保证新博客中博文的完整性,特复制到此留存,如需转载请注明新博客地址即可. LZ到目前已经写了九个设计模 ...
- 涉及模式之 装饰器模式详解(与IO不解的情缘)
作者:zuoxiaolong8810(左潇龙),转载请注明出处,特别说明:本博文来自博主原博客,为保证新博客中博文的完整性,特复制到此留存,如需转载请注明新博客地址即可. LZ到目前已经写了九个设计模 ...
- Java 装饰器模式详解
转载请注明出处:http://blog.csdn.net/zhaoyanjun6/article/details/56488020 前言 在上面的几篇文章中,着重介绍了Java 中常见的 IO 相关知 ...
- Javascript设计模式之装饰者模式详解篇
一.前言: 装饰者模式(Decorator Pattern):在不改变原类和继承的情况下动态扩展对象功能,通过包装一个对象来实现一个新的具有原对象相同接口的新的对象. 装饰者模式的特点: 1. 在不改 ...
- 【装饰器设计模式详解】C/Java/JS/Go/Python/TS不同语言实现
简介 装饰器模式(Decorator Pattern)是一种结构型设计模式.将对象放入到一个特殊封装的对象中,为这个对象绑定新的行为,具备新的能力,同时又不改变其原有结构. 如果你希望在无需修改代码的 ...
- python装饰器大详解
1.作用域 在python中,作用域分为两种:全局作用域和局部作用域. 全局作用域是定义在文件级别的变量,函数名.而局部作用域,则是定义函数内部. 关于作用域,我要理解两点:a.在全局不能访问到局部定 ...
- python 函数及变量作用域及装饰器decorator @详解
一.函数及变量的作用 在python程序中,函数都会创建一个新的作用域,又称为命名空间,当函数遇到变量时,Python就会到该函数的命名空间来寻找变量,因为Python一切都是对象,而在命名空间中 ...
- python装饰器使用详解
装饰器 '''装饰器:就是闭包(闭包的一个应用场景) -- 把要被装饰的函数作为外层函数的参数通过闭包操作后返回一个替代版函数 优点: -- 丰富了原有函数的功能 -- 提高了程序的可拓展性''' 开 ...
- 进阶Python:装饰器 全面详解
进阶Python:装饰器 前言 前段时间我发了一篇讲解Python调试工具PySnooper的文章,在那篇文章开始一部分我简单的介绍了一下装饰器,文章发出之后有几位同学说"终于了解装饰器的用 ...
- python装饰器学习详解-函数部分
本文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,如有问题请及时联系我们以作处理 最近阅读<流畅的python>看见其用函数写装饰器部分写的很好,想写一些自己的读书笔记. ...
随机推荐
- 一文了解io.ReadAtLeast函数
1. 引言 io.ReadAtLeast 函数是Go标准库提供的一个非常好用的函数,能够指定从数据源最少读取到的字节数.本文我们将从io.ReadAtLeast 函数的基本定义出发,讲述其基本使用和实 ...
- Istio 入门(五):访问控制和流量管理
本教程已加入 Istio 系列:https://istio.whuanle.cn 目录 4, 流量管理 基于版本的路由配置 基于 Http header 的路由配置 故障注入 两种故障注入 比例分配流 ...
- 关于在modelsim中 仿真 ROM IP核 读取不了 mif文件 的解决方法
在modelsim中 仿真 ROM IP核 读取不了 mif文件 . 出现状况: 显示无法打开 rom_8x256.mif 文件 .点开modelsim下面文件的内存列表,可看到内存全为0. 查看自身 ...
- CTF中的神兵利刃-foremost工具之文件分离
原理 Foremost可以依据文件内的文件头和文件尾对一个文件进行分离,或者识别当前的文件是什么文件.比如拓展名被删除.被附加也仍然可以对其分离. 使用 安装: 需要使用这个工具,首先我们需要安装他, ...
- 超详细的mysql总结(DQL)
上一篇文章总结了 DDL.DML的使用,这一篇文章把剩下的 DQL 加上~ DQL(Data Query Language)即数据库查询语言,用来查询所需要的信息,在查询的过程中,需要判断所查询的 ...
- SpringBoot 测试实践 - 1:常用的工具
我自己接触到的一些商业或是开源的基于 SpringBoot 项目,它们大部分是没有测试代码的,test 文件夹只有脚手架初始化生成的那个测试类,跟不同的开发聊到这个话题,发现他们中的大部分没有写测试的 ...
- 使用阿里云ECS和RDS搭建个人博客
一.ECS实例配置 1.重置云服务器ECS密码 前往ECS控制台,点击实例,找到刚才开通的ECS实例(找不到的话就看一下上方的地区是否是你的服务器的地域),点击右侧操作栏中的三个点,找到重置实例密码, ...
- 如何平息WPS for linux启动后,笔记本风扇的怒吼
create:2022-09-06 20:02:45 WPS启动后,点击菜单栏右上角[未同步]按钮,不登录,直接关掉.几秒后,笔记本风扇嗷嗷叫.桌面conky显示wpscloudsvr进程CPU占用8 ...
- Hutool,一个超好用的 Java 工具类库
一.简介 Hutool是一个小而全的Java工具类库,通过静态方法封装,降低相关API的学习成本,提高工作效率,使Java拥有函数式语言般的优雅,让Java语言也可以"甜甜的". ...
- 使用GPU搭建支持玛雅(Maya)和Adobe AI,DW,PS的职校云计算机房
背景 学校为职业学校,计算机教室需要进行Maya.Adobe Illustrator.Adobe Dreamweaver.Adobe PhotoShop等软件的教学.每个教室为35用户.资源需求为4核 ...