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 code
    resumeService.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 eventEmitter
  public 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 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");
    }

    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; }
    }
  }
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

鸿蒙OS开发:【一次开发,多端部署】(app市场首页)项目

一多应用市场首页 介绍 本示例展示了应用市场首页&#xff0c;页面中包括Tab栏、运营横幅、精品应用、精品游戏等。 本示例使用一次开发多端部署中介绍的自适应布局能力和响应式布局能力进行多设备&#xff08;或多窗口尺寸&#xff09;适配&#xff0c;保证应用在不同设备或…

海外仓系统哪家好?闭坑指南,擦亮眼睛选对系统

可以说现在的海外仓系统市场还是比较杂乱的&#xff0c;各种不同类型&#xff0c;不同收费标准的系统比比皆是&#xff0c;这让很多想引进海外仓系统的企业不知所措&#xff0c;不知道怎么选。 今天就聊一下在选择海外仓系统的时候应该如何考量&#xff0c;才能避免被坑&#…

告别红色波浪线:tsconfig.json 配置详解

使用PC端的朋友&#xff0c;请将页面缩小到最小比例&#xff0c;阅读最佳&#xff01; tsconfig.json 文件用于配置 TypeScript 项目的编译选项。如果配不对&#xff0c;就会在项目中显示一波又一波的红色波浪线&#xff0c;警告你这些地方的类型声明存在问题。 一般我们遇到这…

社会工程学:美色你顶得住吗?

背景 近年来&#xff0c;网络钓鱼的手段是屡见不鲜&#xff0c;手段和方式也是层出不穷。钓鱼相关的技术作为一种比较高效的打点方式&#xff0c;越来越多的应用于红蓝对抗当中。本文主要分享一次实战攻防中几个有趣的钓鱼场景。 重点说明&#xff1a;本文分享内容为一次经过授…

【UE5.1 角色练习】06-角色发射火球-part2

目录 效果 步骤 一、火球生命周期 二、添加可被伤害的NPC 三、添加冲量 在上一篇&#xff08;【UE5.1 角色练习】06-角色发射火球-part1&#xff09;基础上继续实现角色发射火球相关功能 效果 步骤 一、火球生命周期 为了防止火球没有命中任何物体而一直移动下去&#…

【软考】下篇 第12章 信息系统架构设计理论与实践

目录 一、信息系统架构的定义二、信息系统架构风格三、信息系统架构分类四、信息系统常用的4种架构模型&#xff08;SCSB&#xff09;五、企业信息系统的总体框架ISA六、TOGAF & ADM七、信息化总体架构方法信息化六要素信息化架构模式信息系统生命周期&#xff08;规分设实…

JS中运算符详解

一&#xff1a;赋值运算符 1 类型 、、-、*、/等 2 如何运行 &#xff0c;是将等号右边的数赋值给左边以为例&#xff0c;let num 5&#xff1b;num2等价于numnum2 二&#xff1a;一元运算符 1 自增运算符 什么是一元运算符 只需要一个操作数就可以运算的运算符 &#x…

AIGC行业的发展前景与市场需求

简介&#xff1a;探讨当前时机是否适合进入AIGC行业&#xff0c;考虑行业发展阶段和市场需求。 方向一&#xff1a;行业前景 AIGC&#xff08;人工智能生成内容&#xff09;行业是近年来随着人工智能技术的快速发展而兴起的一个新兴领域&#xff0c;它涉及到使用人工智能技术来…

Git——pull request详细教程

当我们需要协助其他仓库完成更改时&#xff0c;往往会用到git中的Pull Request操作&#xff0c;从而方便团队的协作管理和代码持续集成。 下面是详细的教程步骤。 一. Fork目标项目 比如说我现在要fork以下Qwen-VL的项目&#xff0c;如图所示&#xff1a; 随后点击Create即可…

官宣|HelpLook现已入驻钉钉应用市场,助力企业知识管理知识

前一阵子OpenAI公司最新的GPT-4o技术震撼发布&#xff0c;人工智能的实际应用前景再次引起行业瞩目&#xff0c;或者被GPT4o的数据分析等特色功能折服。如您正寻求将AI技术融入企业知识管理&#xff0c;不要错过HelpLook&#xff01;HelpLook AI知识库已经正式入驻钉钉应用市场…

零基础小白本地部署大疆上云api(个人记录供参考)

文章目录 运行前准备前后端项目运行1.前端项目&#xff1a; 后端项目运行必须先依靠emqx运行必须先依靠redis运行修改后端项目的application.yml文件 运行前准备 1.保证电脑又node.js环境&#xff0c;可以正常使用npm 2.Java的jdk必须是11及以上版本否则无效 3.下载好emqx,red…

本杀小程序开发实战手册:从构思到上线

一、引言 随着移动互联网的快速发展&#xff0c;剧本杀作为一种新兴的娱乐方式&#xff0c;受到了越来越多年轻人的喜爱。为了满足市场需求&#xff0c;开发一款剧本杀小程序成为了许多创业者和开发者的选择。本文将从构思、设计、开发到上线等方面&#xff0c;为您详细解析剧…

嘴尚绝卤味:健康美味新选择,开启味蕾新旅程!

在这个美食文化繁荣的时代&#xff0c;卤味作为传统小吃界的一颗璀璨明珠&#xff0c;一直深受大众的喜爱。而今天&#xff0c;我要向大家介绍一款不仅美味可口&#xff0c;更注重健康营养的卤味品牌——嘴尚绝卤味。它以其独特的制作工艺和丰富的口感&#xff0c;成为众多卤味…

若依ruoyi-vue element-ui 横向滚动条 动态横向滚动条

动态横向滚动条 因为每次横向滑动都要到底部&#xff0c;引入插件 https://github.com/mizuka-wu/el-table-horizontal-scroll //动态横向滚动条移入样式 .el-table-horizontal-scrollbar :hover{//高度 变大10%transform: scaleY(1.5) translateY(-10%);//百分之八十亮度&a…

HTML静态网页成品作业(HTML+CSS)——动漫海绵宝宝介绍网页(5个页面)

&#x1f389;不定期分享源码&#xff0c;关注不丢失哦 文章目录 一、作品介绍二、作品演示三、代码目录四、网站代码HTML部分代码 五、源码获取 一、作品介绍 &#x1f3f7;️本套采用HTMLCSS&#xff0c;未使用Javacsript代码&#xff0c;共有5个页面。 二、作品演示 三、代…

C++贪心算法(3)

整数区间 #include<bits/stdc.h> using namespace std; int main() {int n;cin>>n;int a[110][10]{0};for(int i0;i<n;i){cin>>a[i][1]>>a[i][2];}int cnt[110]{0};int mi99999;int mii-1;bool f[110]{false,false,false,false,false,false,false,…

mybatis-plus代码生成器【一看就会,复制即用】

环境 jdk 17、mysql 8、springboot 3.1.2 POM依赖 <dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-core</artifactId><version>3.5.6</version></dependency> <!-- mybatis-plus代码生成依…

建筑施工突发事故应急处置vr安全培训平台

在不断发展的时代背景下&#xff0c;掌握必要的应急安全知识已成为我们生活中不可或缺的一部分。由央企携手我们华锐推出的3D线上应急宣教虚拟体验馆&#xff0c;标志着民众应急安全教育的全新里程碑&#xff0c;不仅突破了传统学习模式的局限&#xff0c;还让每个人都能在灵活…

深入了解时间处理:当前时间显示与格式化

新书上架~&#x1f447;全国包邮奥~ python实用小工具开发教程http://pythontoolsteach.com/3 欢迎关注我&#x1f446;&#xff0c;收藏下次不迷路┗|&#xff40;O′|┛ 嗷~~ 目录 一、引言 二、显示当前时间 1. 导入时间模块 2. 使用time模块获取当前时间 3. 格式化当前…

Python爬虫入门到进阶:解锁网络数据的钥匙

Python爬虫入门到进阶&#xff1a;解锁网络数据的钥匙 一、Python爬虫基础1.1 爬虫基本概念1.2 Python爬虫必备库1.3 第一个爬虫示例 二、实战爬虫实例2.1 爬取天气数据2.2 高级技巧&#xff1a;异步爬虫 三、反爬机制与应对策略3.1 常见反爬机制3.2 应对策略 四、性能优化与安…