C#设计模式(9)——装饰者模式(Decorator Pattern)

一、引言

在软件开发中,我们经常想要对一类对象添加不同的功能,例如要给手机添加贴膜,手机挂件,手机外壳等,如果此时利用继承来实现的话,就需要定义无数的类,如StickerPhone(贴膜是手机类)、AccessoriesPhone(挂件手机类)等,这样就会导致 ”子类爆炸“问题,为了解决这个问题,我们可以使用装饰者模式来动态地给一个对象添加额外的职责。下面让我们看看装饰者模式。

二、装饰者模式的详细介绍

2.1 定义

装饰者模式以对客户透明的方式动态地给一个对象附加上更多的责任,装饰者模式相比生成子类可以更灵活地增加功能。

2.2 装饰者模式实现

这里以手机和手机配件的例子来演示装饰者模式的实现,具体代码如下:

/// <summary>/// 手机抽象类,即装饰者模式中的抽象组件类/// </summary>public abstract class Phone{public abstract void Print();}/// <summary>/// 苹果手机,即装饰着模式中的具体组件类/// </summary>public class ApplePhone:Phone{/// <summary>/// 重写基类方法/// </summary>public override void Print(){Console.WriteLine("开始执行具体的对象——苹果手机");}}/// <summary>/// 装饰抽象类,要让装饰完全取代抽象组件,所以必须继承自Photo/// </summary>public abstract class Decorator:Phone{private Phone phone;public Decorator(Phone p){this.phone = p;}public override void Print(){if (phone != null){phone.Print();}}}/// <summary>/// 贴膜,即具体装饰者/// </summary>public class Sticker : Decorator{public Sticker(Phone p): base(p){ }public override void Print(){base.Print();// 添加新的行为
            AddSticker();      }/// <summary>/// 新的行为方法/// </summary>public void AddSticker(){Console.WriteLine("现在苹果手机有贴膜了");}}/// <summary>/// 手机挂件/// </summary>public class Accessories : Decorator{public Accessories(Phone p): base(p){}public override void Print(){base.Print();// 添加新的行为
            AddAccessories();          }/// <summary>/// 新的行为方法/// </summary>public void AddAccessories(){Console.WriteLine("现在苹果手机有漂亮的挂件了");}}

此时客户端调用代码如下:

class Customer{static void Main(string[] args){// 我买了个苹果手机Phone phone = new ApplePhone();// 现在想贴膜了Decorator applePhoneWithSticker = new Sticker(phone);// 扩展贴膜行为
            applePhoneWithSticker.Print();Console.WriteLine("----------------------\n");// 现在我想有挂件了Decorator applePhoneWithAccessories = new Accessories(phone);// 扩展手机挂件行为
            applePhoneWithAccessories.Print();Console.WriteLine("----------------------\n");// 现在我同时有贴膜和手机挂件了Sticker sticker = new Sticker(phone);Accessories applePhoneWithAccessoriesAndSticker = new Accessories(sticker);applePhoneWithAccessoriesAndSticker.Print();Console.ReadLine();}

从上面的客户端代码可以看出,客户端可以动态地将手机配件增加到手机上,如果需要添加手机外壳时,此时只需要添加一个继承Decorator的手机外壳类,从而,装饰者模式扩展性也非常好。

2.3 装饰者模式的类图

实现完了装饰者模式之后,让我们看看装饰者模式实现中类之间的关系,具体见下图:

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

  • 抽象构件(Phone)角色:给出一个抽象接口,以规范准备接受附加责任的对象。
  • 具体构件(AppPhone)角色:定义一个将要接收附加责任的类。
  • 装饰(Dicorator)角色:持有一个构件(Component)对象的实例,并定义一个与抽象构件接口一致的接口。
  • 具体装饰(Sticker和Accessories)角色:负责给构件对象 ”贴上“附加的责任。

 

三、装饰者模式的优缺点

看完装饰者模式的详细介绍之后,我们继续分析下它的优缺点。

优点:

  1. 装饰这模式和继承的目的都是扩展对象的功能,但装饰者模式比继承更灵活
  2. 通过使用不同的具体装饰类以及这些类的排列组合,设计师可以创造出很多不同行为的组合
  3. 装饰者模式有很好地可扩展性

缺点:装饰者模式会导致设计中出现许多小对象,如果过度使用,会让程序变的更复杂。并且更多的对象会是的差错变得困难,特别是这些对象看上去都很像。

四、使用场景

下面让我们看看装饰者模式具体在哪些情况下使用,在以下情况下应当使用装饰者模式:

  1. 需要扩展一个类的功能或给一个类增加附加责任。
  2. 需要动态地给一个对象增加功能,这些功能可以再动态地撤销。
  3. 需要增加由一些基本功能的排列组合而产生的非常大量的功能

五、.NET中装饰者模式的实现

在.NET 类库中也有装饰者模式的实现,该类就是System.IO.Stream,下面看看Stream类结构:

上图中,BufferedStream、CryptoStream和GZipStream其实就是两个具体装饰类,这里的装饰者模式省略了抽象装饰角色(Decorator)。下面演示下客户端如何动态地为MemoryStream动态增加功能的。

 MemoryStream memoryStream = new MemoryStream(new byte[] {95,96,97,98,99});// 扩展缓冲的功能BufferedStream buffStream = new BufferedStream(memoryStream);// 添加加密的功能CryptoStream cryptoStream = new CryptoStream(memoryStream,new AesManaged().CreateEncryptor(),CryptoStreamMode.Write);// 添加压缩功能GZipStream gzipStream = new GZipStream(memoryStream, CompressionMode.Compress, true);

六、总结

到这里,装饰者模式的介绍就结束了,装饰者模式采用对象组合而非继承的方式实现了再运行时动态地扩展对象功能的能力,而且可以根据需要扩展多个功能,避免了单独使用继承带来的 ”灵活性差“和”多子类衍生问题“。同时它很好地符合面向对象设计原则中 ”优先使用对象组合而非继承“和”开放-封闭“原则

 

本专题所有源码:设计模式之装饰者模式

 

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

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

相关文章

nosql_探索NoSQL系列

nosql数据科学 (Data Science) Knowledge on NoSQL databases seems to be an increasing requirement in data science applications, yet, the taxonomy is so diverse and problem-centered that it can be a challenge to grasp them. This post attempts to shed light on…

C++TCP和UDP属于传输层协议

TCP和UDP属于传输层协议。其中TCP提供IP环境下的数据可靠传输&#xff0c;它事先为要发送的数据开辟好连接通道&#xff08;三次握手&#xff09;&#xff0c;然后再进行数据发送&#xff1b;而UDP则不为IP提供可靠性&#xff0c;一般用于实时的视频流传输&#xff0c;像rtp、r…

程序员如何利用空闲时间挣零花钱

一&#xff1a; 私活 作为一名程序员&#xff0c;在上班之余&#xff0c;我们有大把的时间&#xff0c;不能浪费&#xff0c;这些时间其实都是可以用来挖掘自己潜在的创造力&#xff0c;今天要讨论的话题就是&#xff0c;程序员如何利用空余时间挣零花钱&#xff1f;比如说周末…

python中api_通过Python中的API查找相关的工作技能

python中api工作技能世界 (The World of Job Skills) So you want to figure out where your skills fit into today’s job market. Maybe you’re just curious to see a comprehensive constellation of job skills, clean and standardized. Or you need a taxonomy of ski…

欺诈行为识别_使用R(编程)识别欺诈性的招聘广告

欺诈行为识别背景 (Background) Online recruitment fraud (ORF) is a form of malicious behaviour that aims to inflict loss of privacy, economic damage or harm the reputation of the stakeholders via fraudulent job advertisements.在线招聘欺诈(ORF)是一种恶意行为…

c语言实验四报告,湖北理工学院14本科C语言实验报告实验四数组

湖北理工学院14本科C语言实验报告实验四 数组.doc实验四 数 组实验课程名C语言程序设计专业班级 14电气工程2班 学号 201440210237 姓名 熊帆 实验时间 5.12-5.26 实验地点 K4-208 指导教师 祁文青 一、实验目的和要求1. 掌握一维数组和二维数组的定义、赋值和输入输出的方法&a…

rabbitmq channel参数详解【转】

1、Channel 1.1 channel.exchangeDeclare()&#xff1a; type&#xff1a;有direct、fanout、topic三种durable&#xff1a;true、false true&#xff1a;服务器重启会保留下来Exchange。警告&#xff1a;仅设置此选项&#xff0c;不代表消息持久化。即不保证重启后消息还在。原…

nlp gpt论文_GPT-3:NLP镇的最新动态

nlp gpt论文什么是GPT-3&#xff1f; (What is GPT-3?) The launch of Open AI’s 3rd generation of the pre-trained language model, GPT-3 (Generative Pre-training Transformer) has got the data science fraternity buzzing with excitement!Open AI的第三代预训练语言…

真实不装| 阿里巴巴新人上路指北

新手上路&#xff0c;总想听听前辈们分享他们走过的路。橙子选取了阿里巴巴合伙人逍遥子&#xff08;阿里巴巴集团CEO&#xff09; 、Eric&#xff08;蚂蚁金服董事长兼CEO&#xff09;、Judy&#xff08;阿里巴巴集团CPO&#xff09;的几段分享&#xff0c;他们是如何看待职场…

小程序学习总结

上个周末抽空了解了一下小程序,现在将所学所感记录以便日后翻看;需要指出的是我就粗略过了下小程序的api了解了下小程序的开发流程以及工具的使用,然后写了一个小程序的demo;在我看来,如果有前端基础学习小程序无异于锦上添花了,而我这个三年的码农虽也写过不少前端代码但离专业…

uber 数据可视化_使用R探索您在Uber上的活动:如何分析和可视化您的个人数据历史记录

uber 数据可视化Perhaps, dear reader, you are too young to remember that before, the only way to request a particular transport service such as a taxi was to raise a hand to make a signal to an available driver, who upon seeing you would stop if he was not …

java B2B2C springmvc mybatis电子商城系统(四)Ribbon

2019独角兽企业重金招聘Python工程师标准>>> 一&#xff1a;Ribbon是什么&#xff1f; Ribbon是Netflix发布的开源项目&#xff0c;主要功能是提供客户端的软件负载均衡算法&#xff0c;将Netflix的中间层服务连接在一起。Ribbon客户端组件提供一系列完善的配置项如…

基于plotly数据可视化_[Plotly + Datashader]可视化大型地理空间数据集

基于plotly数据可视化简介(我们将创建的内容)&#xff1a; (Introduction (what we’ll create):) Unlike the previous tutorials in this map-based visualization series, we will be dealing with a very large dataset in this tutorial (about 2GB of lat, lon coordinat…

Centos用户和用户组管理

inux系统是一个多用户多任务的分时操作系统&#xff0c;任何一个要使用系统资源的用户&#xff0c;都必须首先向系统管理员申请一个账号&#xff0c;然后以这个账号的身份进入系统。1、添加新的用户账号使用useradd命令&#xff0c;其语法如下&#xff1a;useradd 选项 用户名-…

划痕实验 迁移面积自动统计_从Jupyter迁移到合作实验室

划痕实验 迁移面积自动统计If you want to use Google Colaboratory to perform your data analysis, for building data pipelines and data visualizations, here is the beginners’ guide to migrate from one tool to the other.如果您想使用Google Colaboratory进行数据分…

数据开放 数据集_除开放式清洗之外:叙述是开放数据门户的未来吗?

数据开放 数据集There is growing consensus in the open data community that the mere release of open data — that is data that can be freely accessed, remixed, and redistributed — is not enough to realize the full potential of openness. Successful open data…

ios android 交互 区别,很多人不承认:iOS的返回交互,对比Android就是反人类。

宁之的奥义2020-09-21 10:54:39点灭只看此人举报给你解答&#xff1a;美国人都是左撇子&#xff0c;所以他们很方便&#x1f436;给你解答&#xff1a;美国人都是左撇子&#xff0c;所以他们很方便&#x1f436;亮了(504)回复查看评论(19)回忆的褶皱楼主2020-09-21 11:01:01点灭…

Servlet+JSP

需要说明的是&#xff0c;其实工具的版本不是主要因素&#xff0c;所以我下面忽略版本。 你能搜到这篇文章&#xff0c;说明你已经知道怎么部署Tomcat&#xff0c;并运行自己的网页了。 但是&#xff0c;我们知道&#xff0c;每次修改源文件&#xff0c;我们总得手工把文件co…

正态分布高斯分布泊松分布_正态分布:将数据转换为高斯分布

正态分布高斯分布泊松分布For detailed implementation in python check my GitHub repository.有关在python中的详细实现&#xff0c;请查看我的GitHub存储库。 介绍 (Introduction) Some machine learning model like linear and logistic regression assumes a Gaussian di…

BABOK - 开篇:业务分析知识体系介绍

本文更新版已挪至 http://www.zhoujingen.cn/itbang/328.html ---------------------------------------------- 当我们作项目时&#xff0c;下面这张图很多人都明白&#xff0c;从计划、构建、测试、部署实施后发现提供的方案并不能真正解决用户的问题&#xff0c;那么我们是…