首页 > 编程语言 >C#中的事件聚合器实现方法

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

时间:2024-05-28 18:33:59浏览次数:21  
标签:聚合 string get C# userId class 事件 new public

概述:_对象之间的关系_是使代码库难以理解和难以维护的原因。为了更好地理解它,我们求助于马丁·福勒(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; }
    }
  }
}

标签:聚合,string,get,C#,userId,class,事件,new,public
From: https://blog.csdn.net/2401_82584055/article/details/139274567

相关文章

  • Visual Studio 智能代码插件:CodeGeeX
    前言在软件开发领域,高效的编程助手一直是提升开发者效率和质量的关键。随着人工智能技术的不断发展,智能编程助手逐渐成为开发者们不可或缺的工具。其中,CodeGeeX作为一款专为VisualStudio设计的免费智能编程助手,凭借其强大的功能和便捷的使用体验,赢得了广大开发者的青睐。Co......
  • html+CSS部分基础运用8
    1.P147实验1,完成页面制作效果。图7-1木兰花令效果图2.P147实验2,完成页面制作效果。项目1<!DOCTYPEhtml><htmllang="en"><head>  <metacharset="UTF-8">  <linktype="text/css">  <title>木兰花令</title>......
  • html+CSS部分基础运用7
    项目1 设计简易灯箱画廊1.实验所需素材在trees文件夹中提供一个MP3文件和18个JPG文件,设计页面时可以使用。2.编程实现简易灯箱画廊,鼠标单击任一个图像超链接,在底部浮动框架中显示大图像,效果如图4-1所示的页面。图4-1简易灯箱画廊项目2 设计支持音频、视频播放的......
  • Captura完全免费的电脑录屏软件
    一、简介1、Captura是一款免费开源的电脑录屏软件,允许用户捕捉电脑屏幕上的任意区域、窗口、甚至是全屏画面,并将这些画面录制为视频文件。这款软件具有多种功能,例如可以设置是否显示鼠标、记录鼠标点击、键盘按键、计时器以及声音等。此外,Captura还能从网络摄像头捕获视频......
  • 请描述一下 cookies sessionStorage和localstorage区别
    Cookies、sessionStorage和localStorage都是Web浏览器提供的客户端存储机制,但它们之间有一些重要的区别:存储容量:Cookies最大容量约为4KB。sessionStorage和localStorage的容量都约为5MB。有效期:Cookies有明确的过期时间,可以设置为在浏览......
  • React中何时使用memo、useCallback、useMemo以及useRef进行性能优化
    react无法做到像vue一样自动收集依赖更新(期待react19的ReactCompiler),需要开发人员手动的进行性能优化,此时memo、useCallback、useMemo、useRef就是性能优化中的重要API本文虽然介绍可应用场景,但是正常开发中,尤其是useCallback。除非遇到性能问题或者组件库封装,亦或......
  • 在生产服务器 Git clone 一个 Laravel 私有仓库
    本教程以aaPanel为例,请根据laravel版本安装好对应phpnginxmysqlredis等web环境所需然后安装好php所需扩展,比如fileinforedis等 将php的禁用函数开启putenv()proc_open()proc_get_status() 记得重启php然后应用安装PM2Manager,也就是安装node......
  • Docker升级MySQL版本的快速方法
    Docker升级MySQL版本的快速方法背景虽然容器跑数据库用于生产不太靠谱因为性能以及其他相关的问题但是用在测试环境上面还是非常方便的昨天有客户想问问最新版的MySQL的兼容性情况今天告知要验证一把最新版本的数据库的情况.所以这里验证一下,遇到了几个小坑.关于mys......
  • synchronized原理
    对象头(markword,数组长度,类型指针)  实例数据(字段1,字段2) 对齐填充(对其字节)synchronized修饰方法多了一个ACC_SYNCHRONIZED标识符synchronized修饰代码块monitorenter和monitorexitObjectMonitor里_EntryList和_WaitSet1.线程在竞争synchronized锁的时候,jvm首......
  • 【QT6】pycharm集成qt desinger(非anaconda等环境下)
    前言已经安装好了PyQT6,如果没有,请自行选择在项目或者全局打开cmd并输入:pipinstallPyQt6来进行安装!开始安装确定自己是否有安装pyside6,如果有,直接跳到下一步。。如果你没有安装过pyside6,任意地方打开cmd,输入:pipinstallpySide6安装完毕后,找到你python的安装目录:然后点进......