c#装饰器模式详解

基础介绍:

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

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

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

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

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

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

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

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

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

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

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

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

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

  

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

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

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

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

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

应用场景:

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

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

创建方式:

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

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

 1     /// <summary>2     /// 手机类3     /// </summary>4     public class Phone5     {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 Phone5     {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.rhkb.cn/news/187248.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C# 同步异步大白话

同步异步大白话 背景 任务异步编程模型&#xff08;TAP&#xff09;提供了对异步代码的抽象。您可以像往常一样&#xff0c;将代码编写为一系列语句。您可以阅读该代码&#xff0c;就好像每条语句都在下一条语句开始之前完成一样。编译器执行许多转换&#xff0c;因为其中一些…

VulnHub Nullbyte

一、信息收集 1.nmap扫描 arp-scan -l扫描内网存活主机 ┌──(root&#x1f480;kali)-[~/桌面] └─# nmap -sS -A -p- 192.168.103.201/24 -sS 半扫描 -A 扫描详细信息 -p- 扫描全端口发现开放了80、111、777、50978端口 且发现777端口开放了ssh服务&#xff0c;说明他把…

十个使用Spring Cloud和Java创建微服务的实践案例

在使用Java构建微服务时&#xff0c;许多人认为只要学习一些微服务设计模式就足够了&#xff0c;比如CQRS、SAGA或每个微服务一个数据库。虽然这是正确的&#xff0c;但同时学习一些通用的最佳实践也是很有意义的。本文分享一些最佳实践。 1 设计模块化的微服务 微服务应该专…

计算机技术专业CSIT883系统分析与项目管理介绍

文章目录 前言一、学科学习成果二、使用步骤三、最低出勤要求四、讲座时间表五、项目管理 前言 本课程介绍了信息系统开发中的技术和技术&#xff0c;以及与管理信息技术项目的任务相关的方法和过程。 它研究了系统分析师、客户和用户在系统开发生命周期中的互补角色。 它涵盖…

弹性布局display:flex

弹性布局display:flex 一、弹性布局的特点二、容器的属性1、justify-content1.1 justify-content: center 居中1.2 justify-content: flex-start&#xff08;默认值&#xff09;&#xff1a;左对齐1.3 justify-content: flex-end 右对齐1.4 justify-content:space-between 两端…

黑马程序员微服务SpringCloud实用篇02

SpringCloud实用篇02 0.学习目标 1.Nacos配置管理 Nacos除了可以做注册中心&#xff0c;同样可以做配置管理来使用。 1.1.统一配置管理 当微服务部署的实例越来越多&#xff0c;达到数十、数百时&#xff0c;逐个修改微服务配置就会让人抓狂&#xff0c;而且很容易出错。我…

查找或替换excel换行符ctrl+j和word中的换行符^p,^l

一、excel中 直接上图。使用ctrlh调出替换&#xff0c;查找内容里按ctrlj&#xff08;会出现一个闪的小点&#xff09;&#xff0c;即为换行符。 二、word中 在word中&#xff0c;^p和^l分别代表换行符&#xff08;enter&#xff09;和手动换行符&#xff08;使用shiftenter&…

亚马逊云科技Zero ETL集成全面可用,可运行近乎实时的分析和机器学习

亚马逊云科技数据库、数据分析和机器学习全球副总裁Swami Sivasubramanian曾指出&#xff1a;“数据是应用、流程和商业决策的核心。”如今&#xff0c;客户常用的数据传输模式是建立从Amazon Aurora到Amazon Redshift的数据管道。这些解决方案能够帮助客户获得新的见解&#x…

Win10专业版安装wsl-ubuntu子系统

文章目录 一、查看是否满足安装要求二、管理员权限启动 Windows PowerShell三、启用Windows10子系统功能四、启用虚拟机平台功能五、重启电脑六、下载 Linux 内核更新包&#xff08;适用于 x64 计算机的 WSL2 Linux 内核更新包&#xff09;七、将 WSL 2 设置为默认版本八、打开…

华为gre带验证key案例

配置FW_A。 a.配置接口的IP地址&#xff0c;并将接口加入安全区域。 system-view [sysname] sysname FW_A [FW_A] interface GigabitEthernet 1/0/1 [FW_A-GigabitEthernet1/0/1] ip address 1.1.1.1 24 [FW_A-GigabitEthernet1/0/1] quit [FW_A] interface GigabitEthernet 1/…

Python数据容器(字符串)

字符串 1.字符串 字符串也是数据容器的一种&#xff0c;字符串是字符的容器&#xff0c;一个字符串可以存放任意数量的字符。 2.字符串的下标索引 从前向后&#xff0c;下标从0开始从后向前&#xff0c;下标从-1开始 # 通过下标索引获取特定位置的字符 name python print(na…

【技术类-01】doc转PDF程序卡死的解决方案,

摘要&#xff1a; 1、报错&#xff1a; raise AttributeError("%s.%s" % (self._username_, attr))&#xff09; 2、表现&#xff1a;doc转PDF卡死&#xff08;白条不动或出现以上英文&#xff09; 3、解决&#xff1a;在docx保存代码行后面加上time.sleep(3) 4、…

计算机是如何进行工作的+进程和线程

一)计算机是如何工作的? 指令是如何执行的?CPU基本工作过程&#xff1f; 假设上面有一些指令表&#xff0c;假设CPU上面有两个寄存器A的编号是00&#xff0c;B的编号是01 1)第一个指令0010 1010&#xff0c;这个指令的意思就是说把1010地址上面的数据给他读取到A寄存器里面 2…

ubuntu 16.04.5 安装 vivado 2019.1 完整编译AD9361的环境

一、前期安装 1、安装ncurses库&#xff08;已经包含了&#xff0c;其他的os需要安装&#xff09; sudo apt install libncurses5二、安装 sudo ./xsetup使用lic进行激活。 三、安装后 输入指令 sudo gedit ~/.bashrc 末尾添加 source /opt/Xilinx/Vivado/2019.1/setti…

生态环境领域基于R语言piecewiseSEM结构方程模型

结构方程模型&#xff08;Sructural Equation Modeling&#xff0c;SEM&#xff09;可分析系统内变量间的相互关系&#xff0c;并通过图形化方式清晰展示系统中多变量因果关系网&#xff0c;具有强大的数据分析功能和广泛的适用性&#xff0c;是近年来生态、进化、环境、地学、…

ruoyi前后端分离版本开发框架解读---让你快速入门

后端结构 com.ruoyi ├── common // 工具类 │ └── annotation // 自定义注解 │ └── config // 全局配置 │ └── constant // 通用常量 │ └── core …

10. GPIO中断

10. GPIO中断 回顾stm32中断系统STM32中断向量表中断向量偏移NVIC中断控制器 Cortex_A7 中断系统中断向量表GIC控制器中断IDGIC逻辑分块CP15协处理器c0寄存器c1寄存器c12寄存器c15寄存器 中断使能中断优先级设置优先级数配置 GICC_PMR抢占优先级和子优先级位数设置 GICC_BPR优先…

Vue中的 配置项 setup

setup 是 Vue3 中的一个全新的配置项&#xff0c;值为一个函数。 setup 是所有 Composition API&#xff08;组合式API&#xff09;的入口&#xff0c;是 Vue3 语法的基础。 组件中所用到的数据、方法、计算属性等&#xff0c;都需要配置在 setup 中。 setup 会在 beforeCre…

使用WinDbg分析CPU100%的问题

在我们软件运行的时候&#xff0c;偶尔会出现CPU占比100%的问题&#xff0c;而且极其不容易排查&#xff0c;概率极低&#xff0c;我硬是操作了一个下午&#xff0c;出现了一次&#xff0c;然后找到了dmp文件&#xff0c;也没有任何的规律&#xff0c;那么就可以借助windbg进行…

好用的vscode插件

一、代码管理 git GitLens — Git supercharged Git History gitignore 项目管理 Project Manager 管理多个项目 Todo Tree 快速定位代码中的todo WakaTime 用于在编程活动中自动统计工作量、代码提交和时间跟踪等 VS Code Counter 该插件用于帮助我们统计项目代码的行数…