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.mzph.cn/news/95895.shtml

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

相关文章

时序预测 | MATLAB实现EMD-iCHOA+GRU基于经验模态分解-改进黑猩猩算法优化门控循环单元的时间序列预测

时序预测 | MATLAB实现EMD-iCHOAGRU基于经验模态分解-改进黑猩猩算法优化门控循环单元的时间序列预测 目录 时序预测 | MATLAB实现EMD-iCHOAGRU基于经验模态分解-改进黑猩猩算法优化门控循环单元的时间序列预测预测效果基本介绍程序设计参考资料 预测效果 基本介绍 EMD-iCHOAGR…

【C语言】利用数组处理批量数据(字符数组)

前言:前面已经介绍了&#xff0c;字符数据是以字符的ASCII代码存储在存储单元中的&#xff0c;一般占一个字节。由于ASCII代码也属于整数形式&#xff0c;因此在C99标准中&#xff0c;把字符类型归纳为整型类型中的一种。 &#x1f496; 博主CSDN主页:卫卫卫的个人主页 &#x…

(32)测距仪(声纳、激光雷达、深度摄影机)

文章目录 前言 32.1 单向测距仪 32.2 全向性近距离测距仪 32.3 基于视觉的传感器 前言 旋翼飞机/固定翼/无人车支持多种不同的测距仪&#xff0c;包括激光雷达&#xff08;使用激光或红外线光束进行距离测量&#xff09;、360 度激光雷达&#xff08;可探测多个方向的障碍…

Java中阻塞队列原理、特点、适用场景

文章目录 阻塞队列对比、总览阻塞队列本质思想主要队列讲解ArrayBlockingQueueLinkedBlockingQueueSynchronousQueueLinkedTransferQueuePriorityBlockingQueueDelayQueueLinkedBlockingDeque 阻塞队列对比、总览 阻塞队列本质思想 阻塞队列都是线程安全的队列. 其最主要的功能…

MyCat安装文档

JDK安装 JDK具体安装步骤如下&#xff1a; 1. 上传安装包 使用FinalShell自带的上传工具将jdk的二进制发布包上传到Linux 由于上述在进行文件上传时&#xff0c;选择的上传目录为根目录 /&#xff0c;上传完毕后&#xff0c;我们执行指令 cd / 切换到根目录下&#xff0c;查…

基于引力搜索优化的BP神经网络(分类应用) - 附代码

基于引力搜索优化的BP神经网络&#xff08;分类应用&#xff09; - 附代码 文章目录 基于引力搜索优化的BP神经网络&#xff08;分类应用&#xff09; - 附代码1.鸢尾花iris数据介绍2.数据集整理3.引力搜索优化BP神经网络3.1 BP神经网络参数设置3.2 引力搜索算法应用 4.测试结果…

【进阶C语言】排序函数(qsort)与模拟实现(回调函数的实例)

本章大致内容目录&#xff1a; 1.认识回调函数 2.排序函数qsort 3.模拟实现qsort 回调函数为C语言重要知识点&#xff0c;以函数指针为主要知识&#xff1b;下面介绍回调函数的定义、回调函数的库函数举例即库函数模拟实现。 一、回调函数 1.回调函数定义 回调函数就是一…

哈希应用之位图

文章目录 1.位图概念2.面试题引入3.代码解决[配注释]4.位图应用4.1找到100亿个整数里只出现一次的整数4.2找两个分别有100亿个整数的文件的交集[只有1G内存]1.法一[使用于数据量<42亿]2.法二[适用于数据量大>42亿]3.在一个有100亿个int的文件中找到出现次数不超过2次的所…

文心一言 VS 讯飞星火 VS chatgpt (107)-- 算法导论10.1 5题

五、用go语言&#xff0c;栈插入和删除元素只能在同一端进行&#xff0c;队列的插入操作和删除操作分别在两端进行&#xff0c;与它们不同的&#xff0c;有一种双端队列(deque)&#xff0c;其插入和删除操作都可以在两端进行。写出4个时间均为 O(1)的过程&#xff0c;分别实现在…

Python逐日填补Excel中的日期并用0值填充缺失日期的数据

本文介绍基于Python语言&#xff0c;读取一个不同的列表示不同的日期的.csv格式文件&#xff0c;将其中缺失的日期数值加以填补&#xff1b;并用0值对这些缺失日期对应的数据加以填充的方法。 首先&#xff0c;我们明确一下本文的需求。现在有一个.csv格式文件&#xff0c;其第…

Vscode配置C#编程环境(win10)

目录 1、安装好Vscode 2、下载安装.NetCore SDK 3、配置C#环境 3.1 打开Vscode并下载扩展 3.2 Vscode中打开文件夹并配置环境 3.3 调试运行 1、安装好Vscode 2、下载安装.NetCore SDK 官网如下&#xff0c;下载完成后双击打开一路走到底就行.NetCore SDK官网 软件显示安…

GEE错误——Line 2: ee.Image(...).filterBounds is not a function

错误&#xff1a; 我正在尝试通过应用过滤器绑定和过滤器日期来提取多个区域的平均碳含量。我得到的错误是&#xff1a;filterbound 不是一个函数。 我认为问题在于我使用的是 ee.Image 而不是 ee.ImageCollection。我知道如何解决这个问题吗&#xff1f;谢谢 这里的代码&am…

CentOS 7 上编译和安装 SQLite 3.9.0

文章目录 可能报错分析详细安装过程 可能报错分析 报错如下&#xff1a; django.core.exceptions.ImproperlyConfigured: SQLite 3.9.0 or later is required (found 3.7.17). 原因&#xff1a;版本为3.7.太低了&#xff0c;需要升级到3.9.0至少 详细安装过程 1.安装所需的…

vue-img-cutter 实现图片裁剪[vue 组件库]

借助 vue-img-cutter 可以在网页端实现图片裁剪功能&#xff0c;最终功能效果如下&#xff1a; 组件 npm 安装 npm install vue-img-cutter2 --save-dev # for vue2 npm install vue-img-cutter3 --save-dev # for vue3vue-img-cutter使用 template模板标签模块&#xff0c…

socket.error: [Errno 10049]错误

今天在pycharm运行rl_server_no_training.py欲启动服务器时&#xff0c;却出现如下错误 Traceback (most recent call last):File "xxx/rl_server_no_training.py", line 333, in <module>main()File "xxx/rl_server_no_training.py", line 326, in…

linux常见命令以及jdk,tomcat环境搭建

目录 Is pwd cd touch cat echo vim 复制粘贴 mkdir rm cp jdk部署 1. yum list | grep jdk进行查找​编辑 2.安装​编辑 3.再次确认 4.判断是否安装成功 tomcat安装 1.下载压缩包&#xff0c;把压缩包上传至linux(可能需要yum install lrzsz) 2.解压缩unzip 压缩包名&…

云安全之访问控制的常见攻击及防御

访问控制攻击概述 访问控制漏洞即应用程序允许攻击者执行或者访问某种攻击者不具备相应权限的功能或资源。 常见的访问控制可以分为垂直访问控制、水平访问控制及多阶段访问控制 (上下文相关访问控制)&#xff0c;与其相应的访问控制漏洞为也垂直越权漏洞(普通用户可以访问或…

C++:模板进阶与继承

模板进阶与继承 模板进阶1.非类型的模板参数2.模板的特化2.1特化的概念2.2函数模板特化2.3类模板特化2.4全特化和偏特化2.4.1全特化2.4.2偏特化 3.模板的分离编译3.1同文件分离3.2不同文件下分离 继承1.继承的概念和定义1.1继承的概念1.2继承的定义1.2.1定义格式1.2.2继承关系和…

找不到vcomp100.dll解决教程,一键修复vcomp100.dll丢失问题

vcomp100.dll是一个动态链接库&#xff08;DLL&#xff09;文件&#xff0c;。DLL文件是Windows操作系统中的重要组件&#xff0c;它们包含可由多个程序共享的代码和数据。通过使用DLL文件&#xff0c;程序可以实现模块化设计&#xff0c;提高代码的可重用性和可维护性。如果电…