C# 设计模式(结构型模式):装饰器模式

C# 设计模式(结构型模式):装饰器模式

在软件开发中,面对需要扩展功能但又不想修改已有代码的情况时,装饰模式(Decorator Pattern)是一个非常有用的设计模式。装饰模式允许我们在不改变对象自身的情况下,动态地为其添加新的功能。它通过创建一个装饰器类来包裹原始对象,从而增强对象的行为。

1. 装饰模式的定义

装饰模式是一种结构型设计模式,主要用于在不改变对象结构的前提下,动态地为对象添加额外的职责。装饰模式通过创建一个包装类来“装饰”目标对象,并且该包装类能够增强或修改目标对象的行为。

2. 装饰模式的结构

装饰模式通常包括以下几个部分:

  • Component(组件接口):定义了一个基本接口,描述了具体类和装饰器类共同遵循的操作方法。
  • ConcreteComponent(具体组件):实现了组件接口,表示需要被装饰的原始对象。
  • Decorator(装饰器类):实现了组件接口,并持有一个组件实例,在装饰器类中增强或修改该组件的行为。
  • ConcreteDecorator(具体装饰器类):继承自装饰器类,实现对具体功能的扩展。
3. 装饰模式的应用场景

装饰模式适用于以下几种场景:

  • 当你希望在不修改原有代码的情况下,向对象添加额外的功能。
  • 当对象的功能扩展非常复杂,无法通过继承来实现时,使用装饰模式可以动态地组合不同的功能。
  • 当你需要以透明的方式增强对象的功能,且希望增强功能可以在运行时自由选择。
4. C# 实现装饰模式

假设我们有一个简单的饮料类,表示不同类型的饮料。我们希望能够动态地为饮料添加额外的配料(如牛奶、糖等),而不修改原始饮料的代码。我们可以使用装饰模式来实现这一功能。

using System;// 组件接口
public interface IDrink
{string GetDescription();double Cost();
}// 具体组件:咖啡
public class Coffee : IDrink
{public string GetDescription(){return "Coffee";}public double Cost(){return 2.0;}
}// 具体组件:茶
public class Tea : IDrink
{public string GetDescription(){return "Tea";}public double Cost(){return 1.5;}
}// 装饰器类
public abstract class DrinkDecorator : IDrink
{protected IDrink _drink;public DrinkDecorator(IDrink drink){_drink = drink;}public virtual string GetDescription(){return _drink.GetDescription();}public virtual double Cost(){return _drink.Cost();}
}// 具体装饰器:添加牛奶
public class MilkDecorator : DrinkDecorator
{public MilkDecorator(IDrink drink) : base(drink) { }public override string GetDescription(){return _drink.GetDescription() + " + Milk";}public override double Cost(){return _drink.Cost() + 0.5;}
}// 具体装饰器:添加糖
public class SugarDecorator : DrinkDecorator
{public SugarDecorator(IDrink drink) : base(drink) { }public override string GetDescription(){return _drink.GetDescription() + " + Sugar";}public override double Cost(){return _drink.Cost() + 0.2;}
}// 客户端代码
class Program
{static void Main(string[] args){// 创建一杯咖啡IDrink drink = new Coffee();Console.WriteLine($"{drink.GetDescription()} costs {drink.Cost()}");// 给咖啡添加牛奶drink = new MilkDecorator(drink);Console.WriteLine($"{drink.GetDescription()} costs {drink.Cost()}");// 给咖啡添加糖drink = new SugarDecorator(drink);Console.WriteLine($"{drink.GetDescription()} costs {drink.Cost()}");// 创建一杯茶IDrink tea = new Tea();tea = new MilkDecorator(tea);  // 给茶添加牛奶Console.WriteLine($"{tea.GetDescription()} costs {tea.Cost()}");}
}

在这个例子中:

  • IDrink 是组件接口,定义了饮料的基本方法 GetDescriptionCost
  • CoffeeTea 是具体的组件,分别表示咖啡和茶。
  • DrinkDecorator 是装饰器类,它实现了 IDrink 接口,并持有一个 IDrink 实例,允许我们为饮料添加额外的功能。
  • MilkDecoratorSugarDecorator 是具体的装饰器类,分别为饮料添加牛奶和糖。

通过装饰模式,我们可以动态地为饮料对象添加不同的配料,且不需要修改原有的 CoffeeTea 类。每次增强功能时,我们只需要创建一个新的装饰器类,并将其包装在原始对象上。

5. 装饰模式的优缺点

优点

  • 灵活性高:通过装饰器,可以在不修改原始类的情况下动态地增加功能。
  • 避免类爆炸:通过组合装饰器类来扩展功能,避免了继承层次的膨胀。
  • 增强了对象的功能:可以轻松地为对象添加额外的功能,而不会影响其他对象。

缺点

  • 增加了系统复杂性:装饰器模式可能导致系统中有多个装饰器类,使得代码结构复杂。
  • 过度装饰问题:如果装饰器过多,可能会导致调试和理解代码变得困难。
6. 总结

装饰模式是一个非常灵活的设计模式,适用于需要在运行时为对象动态添加功能的场景。它通过装饰器类来增强目标对象的行为,并允许我们不修改原始对象的代码就能实现功能扩展。掌握装饰模式,可以帮助我们设计出更加灵活、可扩展的系统,尤其适用于那些具有很多扩展功能的对象。


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

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

相关文章

【OAuth2系列】如何使用OAuth 2.0实现安全授权?详解四种授权方式

作者:后端小肥肠 🍇 我写过的文章中的相关代码放到了gitee,地址:xfc-fdw-cloud: 公共解决方案 🍊 有疑问可私信或评论区联系我。 🥑 创作不易未经允许严禁转载。 姊妹篇: 【OAuth2系列】集成微…

传感器与检测技术基础知识

传感器检测系统 检测系统的组成:传感器、信号调理、数握采集、信号处理、信号显示、信号输出、输入设备、稳压电源。 检测系统的基本误差分类:绝对误差、相对误差、引用误差,最大引用误差。 测量系统的误差分类:系统误差、随机误差、粗大误…

决定系数(R²分数)——评估回归模型性能的一个指标

目录 1.定义 2.计算举例 3. 结果分析 1.定义 R(R平方)分数,也称为决定系数,是用来评估回归模型性能的一个指标。它表示自变量解释因变量变异性的比例。R分数的取值范围通常在0到1之间,其值越接近1,说明…

stm32HAL库使LED闪烁

PC13引脚为开漏接法 生成代码时设置为out put open drain gpio out put level 设置为high 1表示熄灭 我们将pa9引脚连接为推挽接法 生成代码时设置为 out put push pull Gpio out put level 设置为low 0 表示熄灭 代码使其亮起再延时0.5秒再熄灭再延时0.5秒

矩阵运算提速——玩转opencv::Mat

介绍:用Eigen或opencv::Mat进行矩阵的运算&#xff0c;比用cpp的vector或vector进行矩阵运算要快吗? 使用 Eigen 或 OpenCV 的 cv::Mat 进行矩阵运算通常比使用 std::vector<int> 或 std::vector<double> 更快。这主要有以下几个原因&#xff1a; 优化的底层实现…

yolo小damo合集

效果如下&#xff1a;这个是图片检测 效果如下&#xff1a;这个是视频检测 效果如下&#xff1a;这个是摄像头检测 1 相关库 除了yolov11所用库之外&#xff0c;本文所用到的额外库为pyqt5&#xff0c;输入指令进行安装 pip install pyqt5 导入所需要的库 import sys fro…

【蓝桥杯研究生组】第14届Java试题答案整理

试题链接&#xff1a;链接 A题 满足条件的答案有&#xff1a;35813116 public class TianShu {public static void main(String[] args) {int ans 0;// 2000.1.1 - 2000000.1.1// 年份是月份的倍数&#xff0c;也是日的倍数for (int year2000; year<2000000; year) {for …

基于Java的超级玛丽游戏的设计与实现【源码+文档+部署讲解】

目 录 1、绪论 1.1背景以及现状 1.2 Java语言的特点 1.3 系统运行环境及开发软件&#xff1a; 1.4 可行性的分析 1.4.1 技术可行性 1.4.2 经济可行性 1.4.3 操作可行性 2、 需求分析 2.1 用户需求分析 2.2功能需求分析 2.3界面设计需求分析…

25考研王道数据机构课后习题-----顺序表链表部分

文章目录 1.顺序表题目2.链表相关题目3.我的个人总结 声明&#xff1a;以下内容来自于B站知名up主白话拆解数据结构&#xff0c;望获悉&#xff1b; 1.顺序表题目 下面的这个说的是&#xff1a;下面的哪一个是组成我们的顺序表的有限序列&#xff0c;这个应该是数据元素&#x…

LLM - 使用 LLaMA-Factory 部署大模型 HTTP 多模态服务 (4)

欢迎关注我的CSDN&#xff1a;https://spike.blog.csdn.net/ 本文地址&#xff1a;https://spike.blog.csdn.net/article/details/144881432 大模型的 HTTP 服务&#xff0c;通过网络接口&#xff0c;提供 AI 模型功能的服务&#xff0c;允许通过发送 HTTP 请求&#xff0c;交互…

学英语学压测:02jmeter组件-测试计划和线程组ramp-up参数的作用

&#x1f4e2;&#x1f4e2;&#x1f4e2;&#xff1a;先看关键单词&#xff0c;再看英文&#xff0c;最后看中文总结&#xff0c;再回头看一遍英文原文&#xff0c;效果更佳&#xff01;&#xff01; 关键词 Functional Testing功能测试[ˈfʌŋkʃənəl ˈtɛstɪŋ]Sample样…

多线程访问FFmpegFrameGrabber.start方法阻塞问题

一、背景 项目集成网络摄像头实现直播功能需要用到ffmpeg处理rtmp视频流进行web端播放 通过网上资源找到大神的springboot项目实现了rtmp视频流转为http请求进行视频中转功能&#xff0c;其底层利用javacv的FFmpegFrameGrabber进行拉流、推流&#xff0c;进而实现了视频中转。 …

医学图像分析工具01:FreeSurfer || Recon -all 全流程MRI皮质表面重建

FreeSurfer是什么 FreeSurfer 是一个功能强大的神经影像学分析软件包&#xff0c;广泛用于处理和可视化大脑的横断面和纵向研究数据。该软件由马萨诸塞州总医院的Martinos生物医学成像中心的计算神经影像实验室开发&#xff0c;旨在为神经科学研究人员提供一个高效、精确的数据…

OKHttp调用第三方接口,响应转string报错okhttp3.internal.http.RealResponseBody@4a3d0218

原因分析 通过OkHttp请求网络&#xff0c;结果请求下来的数据一直无法解析并且报错&#xff0c;因解析时String res response.body().toString() 将toString改为string即可&#xff01;

oceanbase集群访问异常问题处理

1.报错现象 2.问题排查 检查obproxy状态发现为不可用状态 重启obproxy 依次重启Obproxy集群 观察任务状态 重启完成 Obproxy状态正常 3.验证登录 登录成功

ruckus R510升级到Unleashe后不能访问

ruckus R510 是IPQ4019&#xff0c;升级到Unleashe&#xff0c;它弹窗提示 但是这个IP没办法用&#xff0c;访问不了AP。 必应了一下&#xff0c;官方提示用advance ip scanner扫描。 扫描持续好久&#xff0c;发现IP竟然是从主路由获得。 9090的端口不用填&#xff0c;甚至不…

使用R语言绘制标准的中国地图和世界地图

在日常的学习和生活中&#xff0c;有时我们常常需要制作带有国界线的地图。这个时候绘制标准的国家地图就显得很重要。目前国家标准地图服务系统向全社会公布的标准中国地图数据&#xff0c;是最权威的地图数据。 今天介绍的R包“ggmapcn”&#xff0c;就是基于最新公布的地图…

linux上安装MySQL教程

1.准备好MySQL压缩包&#xff0c;并进行解压 tar -xvf mysql-5.7.28-1.el7.x86_64.rpm-bundle.tar -C /usr/local 2.检查是否有mariadb数据库 rpm -aq|grep mariadb 关于mariadb:是MySQL的一个分支&#xff0c;主要由开源社区在维护&#xff0c;采用GPL授权许可 MariaDB的目…

计算机网络基础(7)中科大郑铨老师笔记

应用层 目标&#xff1a;  网络应用的 原理&#xff1a;网络应用协议的概念和实现方面 传输层的服务模型 客户-服务器模式 对等模式(peerto-peer) 内容分发网络  网络应用的 实例&#xff1a;互联网流行的应用层协 议  HTTP  FTP  SMTP / POP3 / IMAP  DNS…

Spring源码分析之事件机制——观察者模式(二)

目录 获取监听器的入口方法 实际检索监听器的核心方法 监听器类型检查方法 监听器的注册过程 监听器的存储结构 过程总结 Spring源码分析之事件机制——观察者模式&#xff08;一&#xff09;-CSDN博客 Spring源码分析之事件机制——观察者模式&#xff08;二&#xff…