c#设计模式-结构型模式 之装饰者模式

🚀介绍

        在装饰者模式中,装饰者类通常对原始类的功能进行增强或减弱。这种模式是在不必改变原始类的情况下,动态地扩展一个对象的功能。这种类型的设计模式属于结构型模式,因为这种模式涉及到两个类型之间的关系,这两个类型是组合在一起的,这种组合关系通常是通过继承来实现的。

        装饰者模式的主要优点是可以在不修改原始类的情况下,通过使用单个类来包装其对象,动态地扩展一个对象的功能。其主要缺点是装饰者模式会导致设计中出现很多小类,如果过度使用,会使程序变得复杂。

👻装饰( Decorator 模式中的角色
  1. 抽象构件(Component)角色 :定义一个抽象接口以规范准备接收附加责任的对象。
  2. 具体构件(Concrete Component)角色 :实现抽象构件,通过装饰角色为其添加一些职责。
  3. 抽象装饰(Decorator)角色 : 继承或实现抽象构件,并包含具体构件的实例,可以通过其子类扩展具体构件的功能。
  4. 具体装饰(ConcreteDecorator)角色 :实现抽象装饰的相关方法,并给具体构件对象添加附加的责任。

🚀案例

我们使用一个案例来对快餐店的点餐功能进行改进,快餐店有炒面、炒饭这些快餐,可以额外附加鸡蛋、培根这些配菜,加配菜需要额外加钱,每个配菜的价钱通常不太一样,那么计算总价就会显得比较麻烦,这时候我们就可以使用装饰者模式,在不改变原始类的情况下,动态扩展对象功能。

🐤首先,创建一个最基本的主食抽象类,定义了价格和类型两个属性,以及获取费用和获取类型两个抽象方法

public abstract class FastFood
{/// <summary>/// 价格/// </summary>public float _price { get; set; }/// <summary>/// 类型/// </summary>public string _desc { get; set; }public FastFood(){}public FastFood(float price, string desc){_price = price;_desc = desc;}/// <summary>/// 获取费用/// </summary>/// <returns></returns>public abstract float GetCost();/// <summary>/// 获取类型/// </summary>/// <returns></returns>public abstract string GetDesc();
}

🐤然后,对于上面的主食抽象类分别增加两个实现类,炒饭和炒面,在这里通过基类的含有(float price, string desc)参数的构造函数分别对价格和类型赋值,如果在此处直接调用了GetDesc,那么此时的炒饭和炒粉是什么都还没加的,因此我们在重写GetDesc加上了"啥都不加"字符

/// <summary>
/// 炒饭
/// </summary>
public class FriedRice : FastFood
{public FriedRice() : base(10, "炒饭"){}public override float GetCost(){return _price;}public override string GetDesc(){return _desc + " 啥都不加";}
}/// <summary>
/// 炒面
/// </summary>
public class FriedNoodles : FastFood
{public FriedNoodles() : base(12, "炒面"){}public override float GetCost(){return _price;}public override string GetDesc(){return _desc + " 啥都不加";}
}

🐤创建一个配料抽象类继承于主食抽象类,并且定义了一个FastFood(主食)类型的属性_fastFood

/// <summary>
/// 配料类
/// </summary>
public abstract class Garnish : FastFood
{public FastFood _fastFood { get; set; }
}

🐤对配料类做两个实现,鸡蛋和培根,通过这两个对象,我们可以动态地给一个FastFood对象添加鸡蛋或培根,并计算出新的价格和描述,这就是装饰者模式的核心思想。

在方法中我们再次重写了获取类型和价格的方法。

GetCost()方法是用来计算总价的,即鸡蛋或培根的价格加上被装饰对象的价格。

GetDesc()方法是用来获取描述的,即鸡蛋或培根的描述加上被装饰对象的描述。

/// <summary>
/// 添加鸡蛋
/// </summary>
public class Egg : Garnish
{public Egg(FastFood fastFood){_fastFood = fastFood;_desc = "鸡蛋";_price = 3;}public override float GetCost(){return _price + _fastFood._price;}public override String GetDesc(){return _desc + _fastFood._desc;}
}/// <summary>
/// 添加培根
/// </summary>
public class Bacon : Garnish
{public Bacon(FastFood fastFood){_fastFood = fastFood;_price = 5;_desc = "培根";}public override float GetCost(){return _price + _fastFood._price;}public override String GetDesc(){return _desc + _fastFood._desc;}
}

🐤测试类

class MyClass
{public static void Main(string[] args){//点一份炒饭FastFood riceFood = new FriedRice();//花费的价格Console.WriteLine(riceFood.GetDesc() + " " + riceFood.GetCost() + "元");//点一份炒面FastFood noodleFood = new FriedNoodles();//花费的价格Console.WriteLine(noodleFood.GetDesc() + " " + noodleFood.GetCost() + "元");//点一份加鸡蛋的炒饭FastFood food1 = new FriedRice();food1 = new Egg(food1);//花费的价格Console.WriteLine(food1.GetDesc() + " " + food1.GetCost() + "元");//点一份加培根的炒面FastFood food2 = new FriedNoodles();food2 = new Bacon(food2);//花费的价格Console.WriteLine(food2.GetDesc() + " " + food2.GetCost() + "元");}
}

🐳运行结果

🚀总结

好处:
  • 饰者模式可以带来比继承更加灵活性的扩展功能,使用更加方便,可以通过组合不同的装饰者对象 来获取具有不同行为状态的多样化的结果。装饰者模式比继承更具良好的扩展性,完美的遵循开闭原则,继承是静态的附加责任,装饰者则是动态的附加责任。
  • 装饰类和被装饰类可以独立发展,不会相互耦合,装饰模式是继承的一个替代模式,装饰模式可以动态扩展一个实现类的功能。

使用场景

当不能采用继承的方式对系统进行扩充或者采用继承不利于系统扩展和维护时。

不能采用继承的情况主要有两类:

  • 第一类是系统中存在大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目爆炸性增长;
  • 第二类是因为类定义不能继承(如final类)

在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。

当对象的功能要求可以动态地添加,也可以再动态地撤销时。

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

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

相关文章

幂级数和幂级数的和函数有什么关系?

幂级数和幂级数的和函数有什么关系&#xff1f; 本文例子引用自&#xff1a;80_1幂级数运算&#xff0c;逐项积分、求导【小元老师】高等数学&#xff0c;考研数学 求幂级数 ∑ n 1 ∞ 1 n x n \sum\limits_{n1}^{\infty}\frac{1}{n}x^n n1∑∞​n1​xn 的和函数 &#xff…

视频监控/视频汇聚/安防视频监控平台EasyCVR配置集群后有一台显示离线是什么原因?

开源EasyDarwin视频监控TSINGSEE青犀视频平台EasyCVR能在复杂的网络环境中&#xff0c;将分散的各类视频资源进行统一汇聚、整合、集中管理&#xff0c;在视频监控播放上&#xff0c;TSINGSEE青犀视频安防监控汇聚平台可支持1、4、9、16个画面窗口播放&#xff0c;可同时播放多…

【计算机网络】因特网中的电子邮件

文章目录 简单邮件传送协议SMTP邮件访问协议POP3IMAPHTTP 参考资料 电子邮件为异步通信媒介 因特网电子邮件系统 电子邮件系统的三个构件&#xff1a;用户代理、邮件服务器、邮件发送和读取协议 用户代理 User Agent 即UA 电子邮件客户端软件&#xff0c;用户与电子邮件系统的接…

面试记录_

1&#xff1a;面试杉岩数据&#xff08;python开发&#xff09; 1.1.1 选择题 for(int i0;i<n;i){for(int j0;j<n;jji) } }O(n) * (O(0) O(n/1) O(n/2) O(n/3) ... O(n/n)) 在最坏情况下&#xff0c;内部循环的迭代次数为 n/1 n/2 n/3 ... n/n&#xff0c;这是…

【QT开发(6)】0926-QT 中加入 fastDDS 通信库的程序使用说明

在智能驾驶中&#xff0c;DDS有可能被广泛使用&#xff0c;因此推出这篇说明教程。 1、基于【QT开发&#xff08;5&#xff09;】教程的项目文档进行开发 2、安装DDS 查看《【eProsima Fast DDS&#xff08;1&#xff09;】安装eProsima Fast DDS》 至少安装: foonathan_m…

论文笔记(整理):轨迹相似度顶会论文中使用的数据集

0 汇总 数据类型数据名称数据处理出租车数据波尔图 原始数据&#xff1a;2013年7月到2014年6月&#xff0c;170万条数据 ICDE 2023 Contrastive Trajectory Similarity Learning with Dual-Feature Attention 过滤位于城市&#xff08;或国家&#xff09;区域之外的轨迹 过…

AOP:分页参数统一校验

需求说明 为了保证系统的安全性&#xff0c;需要对所有的 查询列表 接口&#xff0c;添加分页参数&#xff0c;并对分页参数进行校验&#xff0c; &#xff0c;保证参数的合法性。 比如&#xff0c; pageSize&#xff08;每页显示条数&#xff09;&#xff0c;如果不做校验&a…

完整指南:如何使用 Node.js 复制文件

文件拷贝指的是将一个文件的数据复制到另一个文件中&#xff0c;使目标文件与源文件内容一致。Node.js 提供了文件系统模块 fs&#xff0c;通过该模块可以访问文件系统&#xff0c;实现文件操作&#xff0c;包括拷贝文件。 Node.js 中文件拷贝方法 在 Node.js 中&#xff0c;有…

Python3数据科学包系列(一):数据分析实战

一: 数据分析高级语法&#xff1a;序列(Series) # -*- coding:utf-8 -*-from pandas import Seriesprint(-------------------------------------序列Series定义与取值-------------------------------------------) print("""Series序列可以省略,此时索引号默…

What is an HTTP Flood DDoS attack?

HTTP 洪水攻击是一种针对 Web 和应用程序服务器的第 7 层分布式拒绝服务 &#xff08;DDoS&#xff09; 攻击。HTTP 洪水攻击通过使用 HTTP GET 或 HTTP POST 请求执行 DDoS 攻击。这些请求是有效的&#xff0c;并且针对可用资源&#xff0c;因此很难防范 HTTP 洪水攻击。 匿名…

【AI视野·今日Robot 机器人论文速览 第四十四期】Fri, 29 Sep 2023

AI视野今日CS.Robotics 机器人学论文速览 Fri, 29 Sep 2023 Totally 38 papers &#x1f449;上期速览✈更多精彩请移步主页 Interesting: &#x1f4da;NCF,基于Neural Contact Fields神经接触场的方法实现有效的外部接触估计和插入操作。 (from FAIR ) 操作插入处理结果&am…

Go_原子操作和锁

原子操作和锁 本文先探究并发问题&#xff0c;再探究锁和原子操作解决问题的方式&#xff0c;最后进行对比。 并发问题 首先&#xff0c;我们看一下程序 num该程序表面看上去一步就可以运行完成&#xff0c;但是实际上&#xff0c;在计算机中是分三步运行的&#xff0c;如下…

相机数据恢复!详细步骤解析(2023新版)

和朋友在外面旅游用相机拍了好多有意义的照片和视频&#xff0c;但是导入电脑后不知道是被我删除了还是什么原因&#xff0c;这些照片都不见了&#xff0c;请问有方法恢复吗&#xff1f;” 在数字摄影时代&#xff0c;我们依赖相机记录珍贵的瞬间。然而&#xff0c;相机数据丢失…

LeNet网络复现

文章目录 1. LeNet历史背景1.1 早期神经网络的挑战1.2 LeNet的诞生背景 2. LeNet详细结构2.1 总览2.2 卷积层与其特点2.3 子采样层&#xff08;池化层&#xff09;2.4 全连接层2.5 输出层及激活函数 3. LeNet实战复现3.1 模型搭建model.py3.2 训练模型train.py3.3 测试模型test…

MyBatisPlus(七)等值查询

等值查询 条件查询&#xff1a;使用 Wrapper 对象&#xff0c;传递查询条件。 QueryWrapper&#xff08;不要使用&#xff09; 代码 Testvoid eq() {QueryWrapper<User> wrapper new QueryWrapper<>();wrapper.eq("name", "张三");List<…

httpserver 下载服务器demo

实现效果如下&#xff1a; 图片可以直接显示 cpp h 这些可以直接显示 其他的 则是提示是否要下载 单线程 还有bug 代码如下 先放上来 #include "httpserver.h" #include "stdio.h" #include <stdlib.h> #include <arpa/inet.h> #include…

Vue控制textarea可输入行数限制-案例

控制只能输入六行内容 UI部分代码 //我使用了antd ui库 <a-form-model-item ref"address_group" label"规则描述" prop"address_group" > <a-textarea:rows"6"style"width: 60%"placeholder"一次最多输入6行…

【数据结构】队列和栈

大家中秋节快乐&#xff0c;玩了好几天没有学习&#xff0c;今天分享的是栈以及队列的相关知识&#xff0c;以及栈和队列相关的面试题 1.栈 1.1栈的概念及结构 栈&#xff1a;一种特殊的线性表&#xff0c;其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作…

MySQL数据查询性能如何分析--Explain介绍说明

1、Explain是什么 Explain是MySQL执行查看执行计划命令的指令&#xff0c;使用EXPLAIN关键字可以模拟优化器执行SQL查询语句&#xff0c;从而知道MySQL是如何处理你的SQL语句的。分析你的查询语句或是表结构的性能瓶颈。 2、Explain官网介绍 http://dev.mysql.com/doc/refma…

【MySQL】数据类型(二)

文章目录 一. char字符串类型二. varchar字符串类型2.1 char和varchar比较 三. 日期和时间类型四. enum和set类型4.1 set的查询 结束语 一. char字符串类型 char (L) 固定长度字符串 L是可以存储的长度&#xff0c;单位是字符&#xff0c;最大长度是255 MySQL中的字符&#xff…