C#中的事件聚合器实现方法

概述:_对象之间的关系_是使代码库难以理解和难以维护的原因。为了更好地理解它,我们求助于马丁·福勒(Martin Fowler):事件聚合器是间接的简单元素。在最简单的形式中,您可以让它注册到您感兴趣的所有源对象,并让所有目标对象注册到事件聚合器。事件聚合器通过将源对象中的任何事件传播到目标对象来响应该事件。事件聚合器有很多好处。在本文中,我将展示事件聚合器如何使我们更容易扩展应用程序。给我一个理由!为了展示它如何使我们的代码更易于理解,请查看以下模型:public class User { public string Id { get; set; } public bool IsMarried_对象之间的关系_是使代码库难以理解和难以维护的原因。

想了解更多游戏开发知识,可以扫描下方二维码,免费领取游戏开发4天训练营课程

为了更好地理解它,我们求助于马丁·福勒(Martin Fowler):

图片

事件聚合器是间接的简单元素。在最简单的形式中,您可以让它注册到您感兴趣的所有源对象,并让所有目标对象注册到事件聚合器。事件聚合器通过将源对象中的任何事件传播到目标对象来响应该事件。

事件聚合器有很多好处。在本文中,我将展示事件聚合器如何使我们更容易扩展应用程序。

给我一个理由!

为了展示它如何使我们的代码更易于理解,请查看以下模型:

public class User {public string Id { get; set; }public bool IsMarried { get; set; }
}
public class Resume {public string Description { get; set; }public string UserId { get; set; }public bool IsUserMarried { get; set; }
}
public class Store {public string Title { get; set; }public string OwnerId { get; set; }public bool IsOwnerMarried { get; set; }
}

在这里,并将用户的当前婚姻状况存储在一个名为 的字段中。假设每个实体都是一个聚合根,因此每个实体都有自己的服务:ResumeStoreIsUserMarried

public class ResumeService {private readonly ICollection<Resume> db = new List<Resume> {new Resume {Description = "My current resume",UserId = "1",IsUserMarried = false}};public void SetMaritalStatus(string userId, bool isMarried) {foreach (var resume in db.Where(a => a.UserId.Equals(userId))) {resume.IsUserMarried = isMarried;}}
}
public class StoreService {private readonly ICollection<Store> db = new List<Store> {new Store {Title = "Restaurant",OwnerId = "1",IsOwnerMarried = false}};public void SetMaritalStatus(string ownerId, bool isMarried) {foreach (var store in db.Where(a => a.OwnerId.Equals(ownerId))) {store.IsOwnerMarried = isMarried;}}
}
public class UserService {private readonly ICollection<User> db = new List<User> {new User {Id = "1",IsMarried = false}};private readonly ResumeService resumeService;private readonly StoreService storeService;public UserService(ResumeService resumeService, StoreService storeService) {this.resumeService = resumeService;this.storeService = storeService;}public void GotMarried(string userId) {var user = db.First(a => a.Id.Equals(userId));user.IsMarried = true;// propagate changes to other parts of the coderesumeService.SetMaritalStatus(userId, true);storeService.SetMaritalStatus(userId, true);}
}

ResumeService并且两者都有一个更新用户婚姻状况的方法( )。正如你所看到的,对这两个服务都有依赖性,因为当一个用户结婚时,想要通知其他服务。此代码有效,但有两个缺点:StoreServiceSetMaritalStatusUserServiceUserService

1-实际上不依赖或执行其操作!=>(假依赖关系)UserServiceResumeServiceStoreService

2-每当我们添加存储用户婚姻状况的新实体时,我们必须记住更新!=>(难以扩展)GotMarriedUserService

解决方案:事件聚合器

与其引入依赖项(其他服务),不如调整定义一个事件:UserService

public class MaritalStatusChanged : IEvent {  public MaritalStatusChanged(string userId, bool isMarried) {  UserId = userId;  IsMarried = isMarried;  }  public string UserId { get; }  public bool IsMarried { get; }  
}

然后我们需要更新.首先删除依赖项,然后更新方法:UserServiceGotMarried

public class UserService {  private readonly ICollection<User> db = new List<User> {  new User {  Id = "1",  IsMarried = false  }  };  private readonly IEventEmitter eventEmitterpublic UserService(IEventEmitter eventEmitter) {  this.eventEmitter = eventEmitter;  }  public void GotMarried(string userId) {  var user = db.First(a => a.Id.Equals(userId));  user.IsMarried = true;  // propagate changes to other parts of the code  eventEmitter.Publish(new MaritalStatusChanged(userId, true)); }  
}

所以现在,它只取决于事件发射器。活动发射器是我们的活动总线!它在整个域中发布事件。现在,如果想要了解此事件,我们只需创建一个处理程序。例如,这是一个添加到正文中的处理程序:ResumeService

public class MaritalStatusChangedHandler :  IEventHandler<MaritalStatusChanged> {  private readonly ResumeService service;  public MaritalStatusChangedHandler(ResumeService service) {  this.service = service;  }  public Task Handle(MaritalStatusChanged ev) {  service.SetMaritalStatus(ev.UserId, ev.IsMarried); return Task.CompletedTask;  }  
}

将它们粘在一起:

// 1- create an event bus
var bus = new DefaultEventBus();
// 2- create services
var userService = new UserService(bus);
var resumeService = new ResumeService();
var storeService = new StoreService();
// 3- subscribe
bus.Subscribe<MaritalStatusChanged, ResumeService.MaritalStatusChangedHandler>(new ResumeService.MaritalStatusChangedHandler(resumeService));
bus.Subscribe<MaritalStatusChanged, StoreService.MaritalStatusChangedHandler>(new StoreService.MaritalStatusChangedHandler(storeService));
// 4- someone got married
userService.GotMarried("1");

1- 这将创建事件总线。事件总线实现 IEventEmitter 和 IEventSink。 发布事件并允许您订阅事件。

完整代码:

using libc.eventbus.System;
using libc.eventbus.Types;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;namespace libc.eventbus.tests
{[TestClass]public class Showcase2{[TestMethod]public void Showcase(){// 1- create an event busvar bus = new DefaultEventBus();// 2- create servicesvar userService = new UserService(bus);var resumeService = new ResumeService();var storeService = new StoreService();// 3- subscribebus.Subscribe<MaritalStatusChanged, ResumeService.MaritalStatusChangedHandler>(new ResumeService.MaritalStatusChangedHandler(resumeService));bus.Subscribe<MaritalStatusChanged, StoreService.MaritalStatusChangedHandler>(new StoreService.MaritalStatusChangedHandler(storeService));// 4- someone got marrieduserService.GotMarried("1");}public class UserService{private readonly ICollection<User> _db = new List<User>{new User{Id = "1",IsMarried = false}};private readonly IEventEmitter _eventEmitter;public UserService(IEventEmitter eventEmitter){_eventEmitter = eventEmitter;}public void GotMarried(string userId){var user = _db.First(a => a.Id.Equals(userId));user.IsMarried = true;// propagate changes to other parts of the code_eventEmitter.Publish(new MaritalStatusChanged(userId, true));}}public class ResumeService{private readonly ICollection<Resume> _db = new List<Resume>{new Resume{Description = "My current resume",UserId = "1",IsUserMarried = false}};public void SetMaritalStatus(string userId, bool isMarried){foreach (var resume in _db.Where(a => a.UserId.Equals(userId))) resume.IsUserMarried = isMarried;Console.WriteLine($"{userId} is {(isMarried ? "married" : "single")} now");}public class MaritalStatusChangedHandler : IEventHandler<MaritalStatusChanged>{private readonly ResumeService _service;public MaritalStatusChangedHandler(ResumeService service){_service = service;}public Task Handle(MaritalStatusChanged ev){_service.SetMaritalStatus(ev.UserId, ev.IsMarried);return Task.CompletedTask;}}}public class StoreService{private readonly ICollection<Store> _db = new List<Store>{new Store{Title = "Restaurant",OwnerId = "1",IsOwnerMarried = false}};public void SetMaritalStatus(string userId, bool isMarried){foreach (var store in _db.Where(a => a.OwnerId.Equals(userId))) store.IsOwnerMarried = isMarried;Console.WriteLine($"{userId} is {(isMarried ? "married" : "single")} now");}public class MaritalStatusChangedHandler : IEventHandler<MaritalStatusChanged>{private readonly StoreService _service;public MaritalStatusChangedHandler(StoreService service){_service = service;}public Task Handle(MaritalStatusChanged ev){_service.SetMaritalStatus(ev.UserId, ev.IsMarried);return Task.CompletedTask;}}}public class MaritalStatusChanged : IEvent{public MaritalStatusChanged(string userId, bool isMarried){UserId = userId;IsMarried = isMarried;}public string UserId { get; }public bool IsMarried { get; }}public class User{public string Id { get; set; }public bool IsMarried { get; set; }}public class Resume{public string Description { get; set; }public string UserId { get; set; }public bool IsUserMarried { get; set; }}public class Store{public string Title { get; set; }public string OwnerId { get; set; }public bool IsOwnerMarried { get; set; }}}
}

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

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

相关文章

elastich运维

Elastichsearch是一种高度可扩展的开源全文搜索和分析引擎&#xff0c;可以用来实现快速、高效的数据检索。 集群规划与部署&#xff1a;首先需要根据业务需求规划Elastichsearch集群的节点数量和角色&#xff08;如主节点、副本节点、协调节点等&#xff09;。在部署时&#x…

VMware Workstation 不可恢复错误:(vmui) 错误代码0xc0000094

软件版本 vmware 17 错误情况 VMware Workstation 不可恢复错误&#xff1a;(vmui) Exception 0xc0000094 has occurred. 问题原因 VMware升级到17.0后&#xff0c;将虚拟机环境的【硬件兼容性】升级至Workstation 17.X后&#xff0c;无法修改设备参数。 解决办法 打开需…

企业营收分析难?搞定收入认领月底不加班!

在当今日益激烈的市场竞争中&#xff0c;企业的营收分析不仅是衡量经营成果的关键指标&#xff0c;更是指导企业未来发展的重要依据。然而&#xff0c;对于许多企业来说&#xff0c;营收分析的过程往往繁琐且耗时&#xff0c;尤其是月底结账时&#xff0c;大量的数据和复杂的计…

医疗图像处理2023:Transformers in medical imaging: A survey

医学成像中的transformer:综述 目录 一、介绍 贡献与安排 二、CNN和Transformer 1.CNN 2.ViT 三、Transformer应用于各个领域 1.图像分割 1&#xff09;器官特异性 ①2D ②3D 2&#xff09;多器官类别 ①纯transformer ②混合架构 单尺度 多尺度 3&#xff09;…

fyne表单布局

fyne表单布局 layout.FormLayout就像一个 2 列网格布局 。 package mainimport ("image/color""fyne.io/fyne/v2/app""fyne.io/fyne/v2/canvas""fyne.io/fyne/v2/container""fyne.io/fyne/v2/layout" )func main() {myApp…

Wpf 使用 Prism 实战开发Day27

首页汇总和数据动态显示 一.创建首页数据汇总数据接口 汇总&#xff1a;待办事项的总数已完成&#xff1a;待办事项里面有多少条完成的待办完成比例&#xff1a;已完成和汇总之间的比例备忘录&#xff1a;显示备忘录的总数待办事项&#xff1a;显示待办事项未完成的集合备忘录&…

②单细胞学习-组间及样本细胞比例分析

目录 数据读入 每个样本各细胞比例 两个组间细胞比例 亚组间细胞比例差异分析&#xff08;循环&#xff09; 单个细胞类型亚新间比例差异 ①单细胞学习-数据读取、降维和分群-CSDN博客 比较各个样本间的各类细胞比例或者亚组之间的细胞比例差异 ①数据读入 #各样本细胞…

三、Ollama导入大模型(.Net8+SemanticKernel+Ollama)本地运行自己的大模型

Ollama导入大模型 一、导入Ollama大模型1、使用run命令2、使用Modelfile方式 二、导入自定义大模型&#xff08;Ollama官网以外的大模型&#xff09;三、使用OpenWebUI导入大模型 Ollama可以导入官方提供的大模型&#xff0c;也可以导入huggingface上的自定义大模型&#xff08…

【加密与解密(第四版)】第十四章笔记

第十四章 漏洞分析技术 14.1 软件漏洞原理 缓冲区溢出漏洞&#xff1a;栈溢出 堆溢出、整型溢出&#xff08;存储溢出、计算溢出、符号问题&#xff09; UAF&#xff08;Use-After-Free&#xff09;漏洞 14.2 ShellCode 功能模块&#xff1a;下载执行、捆绑、反弹shell 14.3 …

【NumPy】使用NumPy计算相关系数:详解numpy.corrcoef函数及应用

&#x1f9d1; 博主简介&#xff1a;阿里巴巴嵌入式技术专家&#xff0c;深耕嵌入式人工智能领域&#xff0c;具备多年的嵌入式硬件产品研发管理经验。 &#x1f4d2; 博客介绍&#xff1a;分享嵌入式开发领域的相关知识、经验、思考和感悟&#xff0c;欢迎关注。提供嵌入式方向…

基础8 探索JAVA图形编程桌面:邮件操作组件详解

在一个静谧的午后&#xff0c;卧龙和凤雏相邀来到一家古朴典雅的茶馆。茶馆内环境清幽&#xff0c;袅袅的茶香与悠扬的古筝声交织在一起&#xff0c;营造出一种宁静而祥和的氛围。 卧龙和凤雏坐在茶馆的一角&#xff0c;面前的桌子上摆放着一套精致的茶具。茶香四溢&#xff0c…

C++ STL 中的自定义比较:深入理解相等和等价

STL 中的自定义比较、相等和等价 一、简介二、STL 的排序部分三、STL 的未排序部分四、比较元素五、实现比较器六、总结 一、简介 本文主要讨论了在 STL 中使用自定义比较函数&#xff0c;以及比较操作中的相等和等价概念。 有如下的代码&#xff1a; std::vector< std::…

【C++】牛客——活动安排

✨题目链接&#xff1a; AB31 活动安排 ✨题目描述 给定&#x1d45b;个活动&#xff0c;每个活动安排的时间为[&#x1d44e;&#x1d456;,&#x1d44f;&#x1d456;)。求最多可以选择多少个活动&#xff0c;满足选择的活动时间两两之间没有重合。 ✨输入描述: 第一行…

北交所的股票交易佣金最低是多少?万分之二算低的吗?

北交所的佣金目前最低是万分之二&#xff0c;不过只有少数证券公司是这个标准。普通股票佣金万1&#xff0c;融资利率是4.0%~5.0%&#xff01; 北交所佣金一般是万分之6&#xff0c;北交所全称是北京证券交易所&#xff0c;是一家公司制交易所&#xff0c;北交所的佣金比普通股…

【JVM底层原理,JVM架构详解】

1. JVM简介 1.1 什么是JVM? JVM是Java Virtual Machine(Java虚拟机)的缩写,JVM是一种用于计算设备的规范,它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现的。 主流虚拟机: 虚拟机名称介绍HotSpotOracle/Sun JDK和OpenJDK都使用HotSPo…

人大金仓python驱动安装指引

最好使用虚拟环境&#xff0c;避免各种路径异常问题 在指定目录下创建虚拟环境 python3 -m venv myenv myenv可以是一个路径&#xff0c;当前命令会创建一个叫myenv的目录&#xff0c;目录里放的是虚拟环境所需的可执行文件 激活虚拟环境 source myenv/bin/activate 退出虚…

2024-05-28 服务器开发-不同vs版本的std::string的访问出错问题-记录

摘要: 有一个dll库是使用vs2010编译的, 使用这个dll动态库的工程是vs2019. 这个dll动态库返回一个结构体&#xff0c;其中有个成员使用了std::string。但是遇到了std::string的成员显示被赋值为NULL的情况。 本文对进行分析, 重点在于追踪问题的思路。 问题描述: dll使用vs20…

保护“第二生命线”,科技守护颈椎健康

脊柱支撑着人体重量&#xff0c;汇集着众多血管神经&#xff0c;素有“人体第二生命线”之称。在如今快节奏的时代&#xff0c;人们生活方式也在发生着变化&#xff0c;长期低头看手机、伏案久坐等不良生活习惯引发脊柱健康问题&#xff0c;且呈现年轻化趋势。目前&#xff0c;…

【加密与解密(第四版)】第十二章笔记

第十二章 注入技术 12.1 DLL注入方法 在通常情况下&#xff0c;程序加载 DLL的时机主要有以下3个&#xff1a;一是在进程创建阶段加载输入表中的DLL&#xff0c;即俗称的“静态输人”;二是通过调用 LoadLibrary(Ex)主动加载&#xff0c;称为“动态加载”&#xff1b;三是由于系…

核心三:正确的停止线程

3、核心三&#xff1a;正确的停止线程 3.1 如何正确的停止线程 3.1.1 原理介绍&#xff1a;使用interrupt来通知&#xff0c;而不是强制 线程中断的机制&#xff1a;一个线程来通知要中断线程&#xff08;你好&#xff0c;你现在应该停止了&#xff09;最后的决定是由要中断…