为 ServiceCollection 实现装饰器模式

为 ServiceCollection 实现装饰器模式

Intro

在二十四种设计模式中,有一个模式叫做装饰器模式

一般用来动态地给一个对象添加一些额外的职责,就增加功能来说,装饰模式比生成子类更为灵活,有更好的扩展性,我们也可以借助 Decorator 来实现一个切面逻辑,实现 AOP 的一些功能

使用场景

装饰模式是为已有功能动态地添加更多功能的一种方式

当系统需要新功能的时候,是向旧的类中添加新的代码,这些新加的代码通常装饰了原有类的核心职责或主要行为,但是往往会在主类中加入新的字段/方法/逻辑,从而增加了主类的复杂度, 而这些新加入的东西仅仅是为了满足一些只在某种特定情况下才会执行的特殊行为的需要

装饰模式提供了一个很好的方案,它把每个要装饰的功能放在单独的类中,并让这个类包装它要装饰的对象, 当需要执行特殊行为时,就可以在运行时根据需要有选择地、按顺序地使用装饰功能包装对象了。

装饰模式的优点是把类中的装饰功能从类中搬移去除,这样可以简化原有的类,这样做就有效地把类的核心职责和装饰功能区分开了,而且可以去除相关类中重复的装饰逻辑。

Sample

直接来看示例效果吧:

首先我们定义了一个抽象接口 IJob,接口里有一个 Name 属性和一个 Execute 方法

然后定义了一个实现 Sleepy 实现了我们的 IJob 接口,

最后添加了一个装饰器 JobDecorator 也实现了我们的 IJob 接口

private interface IJob
{string Name { get; }void Execute();
}private sealed class Sleepy : IJob
{public string Name => nameof(Sleepy);public void Execute(){Console.WriteLine("Sleeping...");}
}private sealed class JobDecorator : IJob
{private readonly IJob _job;public JobDecorator(IJob job){_job = job;}public string Name => $"??? {_job.Name}";public void Execute(){Console.WriteLine("Before execute");_job.Execute();Console.WriteLine("After execute");}
}

接着我们看使用的示例吧:

var services = new ServiceCollection();
services.AddSingleton<IJob, Sleepy>();
services.Decorate<IJob, JobDecorator>();
using var sp = services.BuildServiceProvider();var job = sp.GetRequiredService<IJob>();
Console.WriteLine(job.Name);
job.Execute();

输出结果如下:

4ce113e1c990dececb6aafe615b606c8.png

output

可以看到我们在原有实现的基础上加入了我们装饰器的逻辑,我们的 BeforeAfter 也都执行了

Implement

Decorate 方法实现如下:

/// <summary>/// Register decorator for TService/// </summary>/// <typeparam name="TService">service type</typeparam>/// <typeparam name="TDecorator">decorator type</typeparam>/// <param name="services">services</param>/// <returns>services</returns>public static IServiceCollection Decorate<TService, TDecorator>(this IServiceCollection services)where TService : classwhere TDecorator : class, TService{return services.Decorate(typeof(TService), typeof(TDecorator));}/// <summary>/// Register service decorator/// </summary>/// <param name="services">services</param>/// <param name="serviceType">serviceType</param>/// <param name="decoratorType">decoratorType</param>/// <returns>services</returns>/// <exception cref="InvalidOperationException">throw exception when serviceType not registered</exception>public static IServiceCollection Decorate(this IServiceCollection services, Type serviceType, Type decoratorType){var service = services.FirstOrDefault(x => x.ServiceType == serviceType);if (service == null){throw new InvalidOperationException("The service is not registed, service need to be registered before decorating");}var objectFactory = ActivatorUtilities.CreateFactory(decoratorType, new[] { serviceType });var decoratorService = new ServiceDescriptor(serviceType, sp => objectFactory(sp, new object?[]{sp.CreateInstance(service)}), service.Lifetime);services.Replace(decoratorService);return services;}

实现逻辑主要是将原来这个 service 的注册从原来的服务替换成 Decorator,Decorator 也实现了服务类型,是可以替换掉服务接口的注册的,实现比较简单,有些情况可能会有问题,主要是实现思路的分享

More

Github 上有一个关于 Decorator 的 issue,感兴趣的看一下:https://github.com/dotnet/runtime/issues/36021

另外有一个开源项目 https://github.com/khellang/Scrutor 已经实现了基于 ServiceCollection 的 Decorator 支持,我们可以借助它来实现 Decorator 模式(原本以为只有服务注册的扩展,偶然间发现还有 decorator 的实现)

使用示例:

var collection = new ServiceCollection();// First, add our service to the collection.
collection.AddSingleton<IDecoratedService, Decorated>();// Then, decorate Decorated with the Decorator type.
collection.Decorate<IDecoratedService, Decorator>();// Finally, decorate Decorator with the OtherDecorator type.
// As you can see, OtherDecorator requires a separate service, IService. We can get that from the provider argument.
collection.Decorate<IDecoratedService>((inner, provider) => new OtherDecorator(inner, provider.GetRequiredService<IService>()));var serviceProvider = collection.BuildServiceProvider();// When we resolve the IDecoratedService service, we'll get the following structure:
// OtherDecorator -> Decorator -> Decorated
var instance = serviceProvider.GetRequiredService<IDecoratedService>();

感兴趣的可以看一下实现,大体上和上面的思路是一样的

References

  • https://greatrexpectations.com/2018/10/25/decorators-in-net-core-with-dependency-injection

  • https://github.com/dotnet/runtime/issues/36021

  • https://github.com/khellang/Scrutor

  • https://github.com/WeihanLi/WeihanLi.Common/blob/cdeac51a1fe65cddc98fe3d1fd1e43917e19aee4/samples/DotNetCoreSample/ServiceDecoratorTest.cs#L7

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

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

相关文章

手把手教你启用Win10的Linux子系统 Ubuntu

1、打开“开发者选项” 2、启用“执行 Linux 程序的windows 子系统” 3、应用商店下载安装Ubuntu 附&#xff1a;ubuntu的一些命令及查看已安装软件包的命令 // 系统 # uname -a # 查看内核/操作系统/CPU信息 # head -n 1 /etc/issue # 查看操作系统版本 # cat…

【地理信息系统GIS】教案(七章全)第五章:空间数据查询与空间分析

目录 第一节 空间数据查询第二节 缓冲区分析第三节 叠置分析第四节 网络分析第五节 DEM建立及分析第一节 空间数据查询 1.1 空间数据查询 1、空间数据查询的含义 从空间数据库中找出所有满足属性约束条件和空间约束条件的地理对象。 空间数据查询的一般过程 2、空间数据查询…

[转]5分钟实现Android中更换头像功能

5分钟实现Android中更换头像功能 写在前面&#xff1a; 更换头像这个功能在用户界面几乎是100%出现的。通过拍摄照片或者调用图库中的图片&#xff0c;并且进行剪裁&#xff0c;来进行头像的设置。 功能相关截图如下&#xff1a; 下面我们直接看看完整吧&#xff1a; public cl…

Excel VBA窗体上打印系统时间print now出错原因及解决方案

如图所示,需要在窗体上显示当前系统时间: 首先,我们看一下now函数的原型: Now 函数   语法:Now   说明:返回一个 Variant (Date),根据计算机系统设置的日期和时间来指定日期和时间。   示例: Private Sub CommandButton1_Click()Dim a As Varianta = NowMsgBox…

(第九周)团队项目14

项目名&#xff1a;食物链教学工具 组名&#xff1a;奋斗吧兄弟 组长&#xff1a;黄兴 组员&#xff1a;李俞寰、杜桥、栾骄阳、王东涵 代码地址&#xff1a;HTTPS: https://git.coding.net/li_yuhuan/FoodChain.git SSH: gitgit.coding.net:li_yuhuan/FoodChain.git SCRUM会议…

为什么 C# 访问 null 字段会抛异常?

一&#xff1a;背景 1. 一个有趣的话题最近在看 硬件异常 相关知识&#xff0c;发现一个有意思的空引用异常问题&#xff0c;拿出来和大家分享一下&#xff0c;为了方便讲述&#xff0c;先上一段有问题的代码。namespace ConsoleApp2 {internal class Program{static Person pe…

C语言试题一百之输入某年某月某日,判断这一天是这一年的第几天

✅作者简介:大家好我是码莎拉蒂,CSDN博客专家🥇🥇🥇 📃个人主页:个人主页 🔥系列专栏:C语言试题200例 💬推荐一款模拟面试、刷题神器👉 点击跳转进入网站 1、题目 题目:输入某年某月某日,判断这一天是这一年的第几天? 分析: 以 3 月 5 日为例,应该先把…

[转]Java学习路线图(完整详细2019版)

一门永不过时的编程语言——Java 软件开发。 Java编程语言占比&#xff1a; 据官方数据统计&#xff0c;在全球编程语言工程师的数量上&#xff0c;Java编程语言以1000万的程序员数量位居首位。 而且很多软件的开发都离不开Java编程&#xff0c;因此其程序员的数量最多。而在…

【CASS精品教程】Win7+CAD2008+CASS9.1(含CASS3D)完美安装教程(附完整软件安装包下载)

本文讲解win764位系统上安装CAD2008+CASS9.1(含CASS3D)免费版安装,文末附完整软件下载地址,亲测可用!!! 文章目录 1. CAD2008安装2. CASS9.1安装3. 软件下载地址1. CAD2008安装 双击安装包中的Setup.exe,开始安装。 点击【安装产品】。

(十一)Jmeter另一种调试工具 HTTP Mirror Server

之前我介绍过Jmeter的一种调试工具Debug Sampler&#xff0c;它可以输出Jmeter的变量、属性甚至是系统属性而不用发送真实的请求到服务器。既然这样&#xff0c;那么HTTP Mirror Server又是做什么用的呢&#xff1f; 一、HTTP Mirror Server的作用&#xff1a; 它可以在本地临…

C语言九十八之实现企业发放的奖金根据利润提成。利润(I)低于或等于 10 万元时,奖金可提 10%;利润高 于 10 万元,低于 20 万元时,低于 10 万元的部分按 10%提成,高于 10 万元的

✅作者简介:大家好我是码莎拉蒂,CSDN博客专家🥇🥇🥇 📃个人主页:个人主页 🔥系列专栏:C语言试题200例 💬推荐一款模拟面试、刷题神器👉 点击跳转进入网站 1、题目 企业发放的奖金根据利润提成。利润(I)低于或等于 10 万元时,奖金可提 10%;利润高 于 10 万…

[转]大数据环境搭建步骤详解(Hadoop,Hive,Zookeeper,Kafka,Flume,Hbase,Spark等安装与配置)

大数据环境安装和配置&#xff08;Hadoop2.7.7&#xff0c;Hive2.3.4&#xff0c;Zookeeper3.4.10&#xff0c;Kafka2.1.0&#xff0c;Flume1.8.0&#xff0c;Hbase2.1.1&#xff0c;Spark2.4.0等&#xff09; 系统说明搭建步骤详述 一、节点基础配置 二、Hadoop安装和配置三、…

C# Any()和AII()方法

我们常常需要的另一类查询是确定数据是否满足某个条件&#xff0c;或者确保所有数据都满足某个条件。例如&#xff0c;需要确定某个产品是否已经脱销(库存为 0)&#xff0c;或者是否发生了某个交易。LINQ 提供了两个布尔方法&#xff1a;Any()和 All()&#xff0c;它们可以快速…

初级图像混合——线性混合操作

addWeighted函数 这个函数的作用是&#xff0c;计算两个数组&#xff08;图像阵列&#xff09;的加权和。原型如下&#xff1a; void addWeighted(InputArray src1, double alpha, InputArray src2, double beta, double gamma, OutputArray dst, int dtype-1); 第一个参数&am…

C语言九十九之实现一个整数,它加上 100 后是一个完全平方数,再加上 168 又是一个完全平方数,请问该数是多少?

✅作者简介:大家好我是码莎拉蒂,CSDN博客专家🥇🥇🥇 📃个人主页:个人主页 🔥系列专栏:C语言试题200例 💬推荐一款模拟面试、刷题神器👉 点击跳转进入网站 一、题目 一个整数,它加上 100 后是一个完全平方数,再加上 168 又是一个完全平方数,请问该数是多…

【专升本计算机】2021年甘肃省专升本计算机全真模拟试题(一)

【专升本计算机】2021年甘肃省专升本计算机全真模拟试题(一) 【专升本计算机】2021年甘肃省专升本计算机全真模拟试题(二) 【专升本计算机】2021年甘肃省专升本计算机全真模拟试题(三) 【专升本计算机】2021年甘肃省专升本计算机全真模拟试题(四) 【专升本计算机】2021…

快速掌握 ASP.NET 身份认证框架 Identity - 通过邮件重置密码

这是 ASP.NET Core Identity 系列的第四篇文章&#xff0c;上一篇文章讲解了如何在 ASP.NET Core Identity 中实现用户登录与登出。这篇文章讲一讲如何在 ASP.NET Core Identity 中通过邮件服务实现用户账号的密码重置。点击上方或后方蓝字&#xff0c;阅读 ASP.NET Core Ident…

[.net 面向对象程序设计深入](4)MVC 6 —— 谈谈MVC的版本变迁及新版本6.0发展方向...

[.net 面向对象程序设计深入]&#xff08;4&#xff09;MVC 6 ——谈谈MVC的版本变迁及新版本6.0发展方向 1.关于MVC 在本篇中不再详细介绍MVC的基础概念&#xff0c;这些东西百度要比我写的全面多了&#xff0c;MVC从1.0到5.0的时间也不短了&#xff0c;很多人只是按照范例去使…

C语言试题101之输入三个整数 x,y,z,请把这三个数由小到大输出

✅作者简介:大家好我是码莎拉蒂,CSDN博客专家🥇🥇🥇 📃个人主页:个人主页 🔥系列专栏:C语言试题200例 💬推荐一款模拟面试、刷题神器👉 点击跳转进入网站 1、题目 题目:输入三个整数 x,y,z,请把这三个数由小到大输出 分析:想办法把最小的数放到 x 上,先…

[转]史上最全的后端技术大全,你都了解哪些技术呢?

导语&#xff1a;工欲善其事&#xff0c;必先利其器&#xff1b;士欲宣其义&#xff0c;必先读其书。后台开发作为互联网技术领域的掌上明珠&#xff0c;一直都是开发者们的追逐的高峰。本文将从后台开发所涉及到的技术术语出发&#xff0c;基于系统开发、架构设计、网络通信等…