c#装饰器模式详解

news2024/11/25 23:27:28
基础介绍:

  动态地给一个对象添加一些额外的职责。适用于需要扩展一个类的功能,或给一个类添加多个变化的情况。

  装饰器,顾名思义就是在原有基础上添加一些功能。

  大家都只知道如果想单纯的给原有类增加一些功能,可以直接继续该类生成一个子类就可以。

  举个例子,如果现在有个手机类,想给手机贴膜,传统的做法就是新建一个手机类的子类(手机贴膜子类),继承自手机类。

  使用这个子类就可以完成对手机的贴膜操作。

  那如果又想给手机按保护壳的话,传统做法有两种,可以继续新建一个手机类的子类(手机保护壳子类),继承自手机类。

  使用这个子类可以给手机按保护壳,但也就失去了给手机贴膜的功能。另一种做法,新建一个手机贴膜类的子类(手机贴膜+保护壳),也就是手机类的子子类。

  这样即可以贴膜也可以按手机壳。

  大家思考一个问题,如果有很多个装饰并且想随意组合的话,那就有N个子类并且存在很深的继承链路。

  想要解决这个问题,就可以用到装饰器了。

  比如贴膜装饰、保护壳装饰、贴纸装饰等等,它们都是独立存在的,只继承自装饰器类。

  什么意思呢?就是说给手机贴膜的时候它并不会给手机按保护壳的功能,职责单一,贴膜装饰器只负责给手机贴膜。

  这样做有什么好处呢?好处就是这些装饰可以随意组合,比如即想贴膜又想按保护壳,就可以将贴膜装饰+保护壳装饰进组组合。

  

  在装饰器模式中各个角色有:

  • 抽象构件(Component)角色:规范手机的构成

  • 具体构件(ConcreteComponent)角色:继承自抽象构件,具体实现手机。(大多情况下,可以省略抽象构件,抽象装饰类可以直接继承)

  • 抽象装饰类(Decorator)角色:创建一个构件(Component)对象的实例,可以使用这个实例调用原构件的功能,并规范装饰类。

  • 具体装饰类(ConcreteDecorator)角色:继承自抽象装饰类,具体实现该装饰功能。

应用场景:

  原有类无法修改或者修改困难的情况下,对类进行多次扩展或功能性比较相互独立,有效防止多次扩展的情况下子类的膨胀。

  注:如果类的扩展比较简单,并且不会多次进行扩展的情况下直接使用类的继承生成子类的方式更为方便快捷。

创建方式:

  为了方便说明,以下实例就不创建抽象构件了。

  1. 首先先看下不使用装饰器进行类的扩展

 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. 使用装饰器模式对类进行扩展

 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     }

从上述实例中可以看出,各个装饰类只对装饰抽象类负责,职责单一。

各个装饰进行组合时,方便随意。新增装饰时,只需要新增一个继承自装饰抽象类的子类即可实现以原有装饰的随意组合使用。

总结:

  想要扩展一个类的时候,传统的继承生成子类的形式,适用于扩展简单,并且不会多次扩展的情况下。

  而如果一个类的扩展是周期性,多次扩展的或功能性比较相互独立的情况下,可以使用装饰器,可以有效的解决传统继承扩展子类膨胀的问题。

  装饰模式是继承的一个替代模式,装饰模式可以动态扩展一个实现类的功能。

文章转载自:少年真爱

原文链接:https://www.cnblogs.com/mingnianjiehunba/p/17732216.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1188887.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

数据结构: unordered_map与unordered_set

目录 1.框架 2.结构 unordered_map unordered_set 3.对HashTable的修改 更改模板参数 4.增加迭代器 a.结构 b.运算符重载 c.HashTable封装迭代器 d.unordered_map与unordered_set的迭代器 1.框架 1.复用HashTable ~~> 增加模板参数KeyOfT 来获取 Key值 unorder…

基于springboot实现致远汽车租赁平台管理系统项目【项目源码+论文说明】

基于springboot实现致远汽车租赁平台系统演示 摘要 首先,论文一开始便是清楚的论述了系统的研究内容。其次,剖析系统需求分析,弄明白“做什么”,分析包括业务分析和业务流程的分析以及用例分析,更进一步明确系统的需求。然后在明白了系统的需求基础上需要进一步地设计系统,主要…

怎么批量获取文件名,并保存到excel?

怎么批量获取文件名&#xff1f;什么叫批量获取文件名&#xff0c;其实也非常好理解&#xff0c;就是面对大量文件是可以一次性的获取所有文件名称&#xff0c;这项技术的应用也是非常常见的&#xff0c;为什么这么说呢&#xff1f;现在很多的文档管理人员或者公司的文员&#…

【AICFD案例教程】汽车外气动-AI加速

AICFD是由天洑软件自主研发的通用智能热流体仿真软件&#xff0c;用于高效解决能源动力、船舶海洋、电子设备和车辆运载等领域复杂的流动和传热问题。软件涵盖了从建模、仿真到结果处理完整仿真分析流程&#xff0c;帮助工业企业建立设计、仿真和优化相结合的一体化流程&#x…

进入网络安全行业有哪些大公司推荐

随着互联网的普及和数字化进程的加速&#xff0c;网络安全问题日益凸显。从个人信息的泄露到国家基础设施的被攻击&#xff0c;网络安全已经不再只是一个技术问题&#xff0c;而是关乎到每个人、每个企业和国家的核心利益。在这场没有硝烟的战争中&#xff0c;一些大公司凭借其…

linux基础指令【上篇】

&#x1f4d9; 作者简介 &#xff1a;RO-BERRY &#x1f4d7; 学习方向&#xff1a;致力于C、C、数据结构、TCP/IP、数据库等等一系列知识 &#x1f4d2; 日后方向 : 偏向于CPP开发以及大数据方向&#xff0c;欢迎各位关注&#xff0c;谢谢各位的支持 引用 01. ls 指令2. pwd命…

IntelliJ Idea 撤回git已经push的操作

最初的样子 现在的样子 解决方案 第一步&#xff0c;commit到本地撤回&#xff1a; 打开提交历史记录&#xff0c;选中回退的版本右键&#xff0c;点击“Reset Current Branch to Here…”,然后选中“Mixed”&#xff0c;点击Reset后&#xff0c;之前commit的代码会在本地显…

定位咨询的价值:企业在市场中如何立足并打造竞争优势?

在激烈的市场竞争中&#xff0c;定位咨询服务显得尤为关键&#xff0c;它既能帮助企业发掘内在优势&#xff0c;又能塑造独特的市场地位&#xff0c;并指导如何持续巩固这一市场地位。 何为定位咨询? 定位咨询&#xff0c;即市场定位咨询&#xff0c;是指咨询公司帮助客户在…

彻底解决Win11锁屏界面黑屏或者图片不变化

问题描述 今天不知道干了啥&#xff0c;一顿操作后&#xff0c;win11的锁屏界面的图片就变成固定的了&#xff0c;原来是有windows聚焦的图片在自动变化的效果&#xff0c;现在没有了。然后就各种搜索求助&#xff0c;第二顿操作之后&#xff0c;锁屏界面彻底变成了黑色&#…

Python从入门到进阶

Python基础入门----Python简介 Python基础入门----安装Python环境&#xff08;Windows、MacOS、CentOS、Ubuntu&#xff09; Python基础入门----Python基础语法&#xff1a;解释器、标识符、关键字、缩进 Python基础入门----Python基本数据类型&#xff1a;数字、字符串、列…

IDEA 编译项目时报错:java: java.lang.OutOfMemoryError:GC overhead limit exceeded解决方法

1.问题简述 在Intellij IDEA下编译Java项目&#xff0c;报错&#xff1a;java.lang.OutOfMemoryError: …(此处忽略) GC overhead limit exceeded 2.问题分析 错误是发生在编译阶段&#xff0c;而不是运行阶段。通过查询相关资料发现&#xff0c; 1.idea编译Java项目使用的虚…

ChromeDriver谷歌浏览器驱动下载安装与使用最新版118/119/120

ChromeDriver谷歌浏览器驱动下载安装与使用最新版118/119/120 1. 确定Chrome版本 我们首先确定自己的Chrome版本 Chrome设置->关于Chrome 可以看到&#xff0c;当前chrome是最新版本&#xff1a;119.0.6045.124&#xff08;正式版本&#xff09; &#xff08;64 位&#…

SOLIDWORKS参数化设计之干涉检查

SOLIDWORKS参数化设计的思路和技巧我们讲过很多了&#xff0c;今天来讲一讲如何在模型完成之后自动执行干涉检查。 SOLIDWORKS软件本身就有干涉检查的功能&#xff0c;在评估选项卡里可以找到该功能&#xff0c;我们这里说的干涉检查指的是静态干涉检查&#xff0c;即模型在静…

WebDAV之π-Disk派盘 + PassStore

大家常用的qq,手机微信,新浪微博等。假如各个网址都设成同样的帐号和登陆密码,一旦某一帐户泄漏了,别的平台上的账户密码都有被撞库攻击的风险。在不一样的站点设定不一样的高韧性登陆密码才算是最安全可靠的确保,殊不知这般繁多的帐户密码是难以记得的。因而,有着一款安…

Echarts示例

一.概念 ECharts&#xff08;Enterprise Charts&#xff09;是百度开源的一个基于JavaScript的可视化图表库。它提供了多种常见的数据可视化图表&#xff0c;包括折线图、柱状图、散点图、饼图、雷达图等等。使用ECharts&#xff0c;用户可以通过简单的配置和接口调用来创建交…

使用Python的requests库采集充电桩LBS位置经纬度信息

目录 一、引言 二、采集数据的流程 1、获取充电桩的URL地址 2、发送HTTP请求获取数据 3、解析数据获取经纬度信息 4、存储数据 三、代码实现 四、注意事项和优化建议 五、充电桩数据的后续利用 六、总结 一、引言 随着电动汽车的普及&#xff0c;充电设施的建设也日…

scss 实用教程

变量 $ 定义变量 $link-color: blue;变量名可以与css中的属性名和选择器名称相同 使用变量 a {color: $link_color; }$highlight-border: 1px solid $link_color;中划线和下划线相互兼容&#xff0c;即中划线声明的变量可以使用下划线的方式引用&#xff0c;反之亦然。 $li…

Power Apps-“编辑“窗体组件

插入一个“编辑”窗体 连接数据源 在该组件的Item函数中编辑筛选符合条件的唯一记录 LookUp(表名,列名值) LookUp参考文档&#xff1a;Filter、Search 和 LookUp 函数&#xff08;包含视频&#xff09; - Power Platform | Microsoft Learn 数据表里的数据就一一对应出现在了组…

邮箱哪家强?哪个牌子邮箱好用

邮箱在国内外使用情况不太一样&#xff0c;国内一般都是工作中需要用邮箱&#xff0c;直接使用公司发的企业邮箱就可以了&#xff0c;个人一般自己需要使用邮箱频率比较少&#xff0c;大多是用来注册其他平台信息&#xff0c;接受验证码、电子发票等等&#xff0c;使用不频繁。…

若依分离版——使用Knife4j 自动生成接口文档

背景&#xff1a; 前后端分离程序&#xff0c;如果需要前端开发人员和后端开发人员配合开发&#xff0c;则需要将接口文档并显性给前端人员 解决办法&#xff1a; 使用knife4j替代若依自带的swagger&#xff0c;因为knife4j是在swagger基础上包装的&#xff0c;Knife4j不仅具…