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.rhkb.cn/news/500579.html

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

相关文章

yolov5核查数据标注漏报和误报

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、误报二、漏报三、源码总结 前言 本文主要用于记录数据标注和模型预测之间的漏报和误报思想及其源码 提示:以下是本篇文章正文内容,…

Word如何插入图片并移动到某个位置

Word如何插入图片并移动到某一个位置 新建word→插入→图片 选择合适的位置→选择图片→打开 点击图片→布局选项→选择文字环绕下的任意一个→固定在页面上 点击图片就可以将图片移动到任意位置

【prometheus】【blackbox_exporter】grafna导入blackbox_exporter看板配置

1、进入到grafana看板,选择合适的看板模版 地址:https://grafana.com/grafana/dashboards/ 在搜索框中输入 blackbox_exporter,找到合适的模版,如下图所示: 2、点击并下载对应看板JSON数据 3、在grafana的页面进行导入操作 3.1…

微服务面试题:分布式事务和服务监控

🧑 博主简介:CSDN博客专家,历代文学网(PC端可以访问:https://literature.sinhy.com/#/?__c1000,移动端可微信小程序搜索“历代文学”)总架构师,15年工作经验,精通Java编…

wx015基于springboot+vue+uniapp的经济新闻资讯的设计与实现

开发语言:Java框架:springbootuniappJDK版本:JDK1.8服务器:tomcat7数据库:mysql 5.7(一定要5.7版本)数据库工具:Navicat11开发软件:eclipse/myeclipse/ideaMaven包&#…

获取用户详细信息-ThreadLocal优化

Thread全局接口可用,不用再重复编写。所以为了代码的复用,使用Thread。把之前的内容(函数的参数和map与username)注释掉,换为Thread传过来的内容(map与username)。 因为Thread需要在拦截器里面…

【论文阅读笔记】IceNet算法与代码 | 低照度图像增强 | IEEE | 2021.12.25

目录 1 导言 2 相关工作 A 传统方法 B 基于CNN的方法 C 交互方式 3 算法 A 交互对比度增强 1)Gamma estimation 2)颜色恢复 3)个性化初始η B 损失函数 1)交互式亮度控制损失 2)熵损失 3)平滑损失 4)总损失 C 实现细节 4 实验 5 IceNet环境配置和运行 1 下载…

git环境配置用户与秘钥

git环境配置用户与秘钥 git环境配置git配置用户名与邮箱git配置秘钥 git环境配置 已经安装git后环境配置 git配置用户名与邮箱 查看git版本 git -v查看git配置环境 git config --global --list第一次未配置时会报无法找到配置文件 全局配置git用户名 git config --glob…

logback日志框架源码分析

目录 (一)入口:slf4j选择日志框架 (二)日志框架初始化 (1)logback的3种配置方式 a、BasicConfigurator默认配置 b、SPI方式配置的Configurator实现类 c、通过配置文件初始化 (2)xml配置文件初始化 (三)Logger的创建 (四)打印日志 本文源码基于:logback版…

SpringBoot整合篇 05、Springboot整合Redission

文章目录 前言Redission详细配置步骤pom依赖application.yaml配置类CacheConfigEnvironmentContext RedissionController单测 前言 本篇博客是SpringBoot整合Redission,若文章中出现相关问题,请指出! 所有博客文件目录索引:博客…

从0入门自主空中机器人-4-【PX4与Gazebo入门】

前言: 从上一篇的文章 从0入门自主空中机器人-3-【环境与常用软件安装】 | MGodmonkeyの世界 中我们的机载电脑已经安装了系统和常用的软件,这一篇文章中我们入门一下无人机常用的开源飞控PX4,以及ROS中无人机的仿真 1. PX4的安装 1.1 PX4固件代码的下载…

支持最新 mysql9的workbench8.0.39 中文汉化教程来了

之前在 B 站上发布了 mysql8 workbench 汉化教程,一年多来帮助很多初学者解决了不熟悉英文的烦恼。 汉化视频可以访问: 2024最新版mysql8.0.39中文版mysql workbench汉化 中文升级 旧版汉化报错解决_哔哩哔哩_bilibili MySql Workbench汉化_哔哩哔哩_…

RC充电电路仿真与分析

RC充电原理 下图是一个常见的RC充电电路:(假设R10K,C100nF) SW断开时,这个电路处于断路状态,C既没有充电也没有放电;SW闭合时,直流电源5V为电容C充电; 充电时电容两端…

(二)编译原生SDK以及配置交叉编译链

文章目录 编译原生SDKLinuxSDK的安装第一步解压LinuxSDK第二步安装依赖软件第三步解压Buildroot的dl文件 Linux系统镜像编译、生成第一步 配置编译环境第二步 编译 LinuxSDK编译上面配置好的 环境配置编译 LinuxSDK配置内核选项配置 Buildroot编译 Qt 库 编译生成 Linux 系统镜…

分布式算法(五):初识ZAB协议

文章目录 一、什么是Zookeeper二、ZAB与Zookeeper的关系为什么Zookeeper不直接使用Paxos 三、ZAB简介1.名词解释提案(Proposal)事务(Transaction)原子广播(Atomic Broadcast) 2.集群角色领导者(…

RabbitMQ基础篇之Java客户端 Topic交换机

文章目录 Topic 交换机概述 Routing Key 与 Binding Key优缺点及场景优点缺点应用场景 案例演示创建队列和交换机:消费者代码:消息发送代码:测试: 总结 Topic 交换机概述 路由机制: Topic交换机与Direct交换机类似&am…

开源模型应用落地-LangChain实用小技巧-使用各种Loader高效解析不同数据源(七)

一、前言 在 LangChain框架中,提供了Loader机制,以统一的方式来从各种数据源获取数据,使得开发人员可以方便地集成不同类型的数据源,而无需为每种数据源编写特定的加载代码。它可以将不同格式的数据转换为 LangChain 可以处理的统…

SSRF服务端请求Gopher伪协议白盒测试

前言 是什么SSRF? 这个简单点说就是 服务端的请求伪造 就是这个如果是个 请求图片的网站 他的目的是请求外部其他网站的 图片 但是 SSRF指的是让他请求本地的图片 再展示出来 请求的是他的服务器上的图片 SSRF(Server-Side Request Forgery:服务器端请求伪造) …

数据可视化-16. 日历图

目录 1. 日历图的概念 2. 日历图的适用场景 2.1 事件或活动的频率分析 2.2 数据的时间周期性分析 2.3 异常值检测 2.4 绩效监控 3. 日历图的缺陷 3.1 粒度受限于天数 3.2 数据密度过高时候难以解读 3.3 难以比较多个数据集 3.4 周期性较长的数据不易展示 4. 日历图…

Flink源码解析之:如何根据JobGraph生成ExecutionGraph

Flink源码解析之:如何根据JobGraph生成ExecutionGraph 在上一篇Flink源码解析中,我们介绍了Flink如何根据StreamGraph生成JobGraph的流程,并着重分析了其算子链的合并过程和JobGraph的构造流程。 对于StreamGraph和JobGraph的生成来说&…