微软官方的开源项目eShopOnContainers中,用到了一个实现中介者模式的类库:MediatR。这个类库的作者叫Jimmy Bogard,在其gtihub主页上可以看到,注明的对象映射组件AutoMapper 就是他写的。其博客上的自我介绍是这么写的:

Headspring的首席架构师,《MVC in Action》的作者,国际演说家,高产的开源软件开发者。擅长分布式系统,REST,消息,领域驱动设计和CQRS。

回到MediatR这个组件,他是一个低调的类库,致力于解决一个简单的问题:解耦进程内消息的发送与处理。跨平台,支持.NET4.5和netstandard1.1。

中介者模式

在继续研究MediatR之前,先回顾下“中介者设计模式(Mediator)”,中介者模式的定义为:用一个中介对象来封装一系列的对象交互。中介者使各对象不需要显式地相互应用,从而使其耦合松散,而且可以独立地改变他们之间的交互。其结构图如下:

以下是一个具体的中介者模式demo:

/// <summary>
/// 抽象中介者
/// </summary>
public abstract class AbstractMediator
{public abstract void SendMessage(string msg, AbstractColleague colleague);
}/// <summary>
/// 抽象同事类
/// </summary>
public abstract class AbstractColleague
{public string Name { get; set; }protected AbstractMediator Mediator;protected AbstractColleague(AbstractMediator mediator){Mediator = mediator;}public abstract void PrintMsg(string msg);
}/// <summary>
/// 具体中介者,负责同事类之间的交互,他必须清楚的知道需要交互的所有同事类的细节。
/// </summary>
public class Mediator : AbstractMediator
{public AbstractColleague ColleagueA;public AbstractColleague ColleagueB;public override void SendMessage(string msg, AbstractColleague colleague){if (colleague == ColleagueA){ColleagueB.PrintMsg(msg);}else if (colleague == ColleagueB){ColleagueA.PrintMsg(msg);}}
}/// <summary>
/// 具体同事类A,他是不知道其他具体同事类的存在的。他与其他同事类的交互,是通过中介者来实现的。
/// </summary>
public class ConcreteColleagueA : AbstractColleague
{public ConcreteColleagueA(AbstractMediator mediator) : base(mediator){}public void SendMessage(string msg){Mediator.SendMessage(msg,this);}public override void PrintMsg(string msg){Console.WriteLine($"A收到消息:{msg}");}
}public class ConcreteColleagueB : AbstractColleague
{public ConcreteColleagueB(AbstractMediator mediator) : base(mediator){}public void SendMessage(string msg){Mediator.SendMessage(msg, this);}public override void PrintMsg(string msg){Console.WriteLine($"B收到消息:{msg}");}
}class Program
{/// <summary>/// 客户端调用/// </summary>/// <param name="args"></param>static void Main(string[] args){var mediator = new Mediator();var colleagueA = new ConcreteColleagueA(mediator);var colleagueB = new ConcreteColleagueB(mediator);mediator.ColleagueA = colleagueA;mediator.ColleagueB = colleagueB;colleagueA.SendMessage("你好B,中午一起饭吧?");colleagueB.SendMessage("你好A,好的。");Console.ReadLine();}
}

程序输出如下:

B收到消息:你好B,中午一起饭吧?
A收到消息:你好A,好的。

中介者类把不同的同事类之间的交互提升到其内部,这样同事类之间的交互变得简单了,同事类不需要知道其他同事类的存在,通过中介者类来完成与其他同事类的交互。另一方面,中介者类本身复杂性增加,中介者类需要知道所有的同事类,例如调用他们的公共方法。

MediatR

MediatR可以与很多依赖注入组件一起工作,其github文档有详细说明。以下是我结合Autofac组件的代码研究。

新建ASP.NET Core Console程序,添加MediatR和Autofac依赖包。然后配置Autofac:

var builder = new ContainerBuilder();
// mediator itself
builder.RegisterType<Mediator>().As<IMediator>().InstancePerLifetimeScope();// request handlers
builder.Register<SingleInstanceFactory>(ctx => {var c = ctx.Resolve<IComponentContext>();return t => c.TryResolve(t, out var o) ? o : null;}).InstancePerLifetimeScope();// notification handlers
builder.Register<MultiInstanceFactory>(ctx => {var c = ctx.Resolve<IComponentContext>();return t => (IEnumerable<object>)c.Resolve(typeof(IEnumerable<>).MakeGenericType(t));}).InstancePerLifetimeScope();//builder.RegisterType<PingHandler>().AsImplementedInterfaces().InstancePerDependency();
builder.RegisterAssemblyTypes(typeof(Program).GetTypeInfo().Assembly).AsImplementedInterfaces();var mediator = builder.Build().Resolve<IMediator>();
Test(mediator);

MediatR可以支持几种模式,有请求/响应模式,发布模式。

请求/响应模式,也可以叫做命令模式,主要适用于命令和查询场景。一个请求只能被一个处理者捕获,如果存在多个处理者,那么只有最后一个处理者会被激活。

以下代码声明消息,然后定义处理者:

/*注意:请求/响应接口适用于命令和查询场景。*都只能有一个Handler,如果注册多个,只有最后一个会生效。*/
public class Ping : IRequest<string>
{public int MsgId { get; set; }
}public class PingHandler : IRequestHandler<Ping, string>
{public Task<string> Handle(Ping request, CancellationToken cancellationToken){return Task.FromResult($"MsgID={request.MsgId},Pong");}
}/// <summary>
/// 为了方便,不需要CancellationToken的Handler,可以继承AsyncRequestHandler类
/// </summary>
public class AsyncNoCancellation : AsyncRequestHandler<Ping, string>
{protected override Task<string> HandleCore(Ping request){return Task.FromResult("Pong");}
}/// <summary>
/// 如果Handler是完全同步的,可以继承RequestHandler类
/// </summary>
public class SyncHandler : RequestHandler<Ping, string>
{protected override string HandleCore(Ping request){return $"SyncHandler Pong";}
}

然后就是发送请求了:

var response = await mediator.Send(new Ping(){MsgId = 100});
Console.WriteLine(response); // "SyncHandler Pong"

另外,请求/响应模式还支持不带任何返回值的处理者:

public class OneWay:IRequest
{public int MsgId { get; set; }
}public class OneWayHandler : IRequestHandler<OneWay>
{public Task Handle(OneWay request, CancellationToken cancellationToken){Console.WriteLine($"{request.MsgId},OneWayHandler");return Task.CompletedTask;}
}

发布模式,一般用于发布一个事件,通知订阅者某件事情已经发生,对此事感兴趣的订阅者可以采取行动了。一般是一个发布这,多个订阅者。

public class Hello : INotification
{public int MsgId { get; set; }
}public class Hello1 : INotificationHandler<Hello>
{public async Task Handle(Hello notification, CancellationToken cancellationToken){await Task.Delay(3000);Console.WriteLine($"{notification.MsgId},{Thread.CurrentThread.ManagedThreadId}");}
}public class Hello2 : INotificationHandler<Hello>
{public async Task Handle(Hello notification, CancellationToken cancellationToken){await Task.Delay(3000);Console.WriteLine($"{notification.MsgId},{Thread.CurrentThread.ManagedThreadId}");}
}

像这样发布消息:

  1. await mediator.Publish(new Hello() {MsgId = 300});

程序输出如下:

300,4
300,5
Main 5

这里可以看到,2个订阅者都被激活了。另外,可以看到不同的订阅者所处的线程ID不一样,他们是异步执行的。

原文地址 :http://coderyu.com/2018/04/02/mediatr-%E4%B8%AD%E4%BB%8B%E8%80%85/

.NET社区新闻,深度好文,欢迎访问公众号文章汇总 http://www.csharpkit.com

MEDIATR 一个低调的中介者类库相关推荐

  1. [译]ASP.NET Core中使用MediatR实现命令和中介者模式

    在本文中,我将解释命令模式,以及如何利用基于命令模式的第三方库来实现它们,以及如何在ASP.NET Core中使用它来解决我们的问题并使代码简洁.因此,我们将通过下面的主题来进行相关的讲解. 什么是命 ...

  2. ASP.NET Core中使用MediatR实现命令和中介者模式

    作者:依乐祝 原文地址:https://www.cnblogs.com/yilezhu/p/9866068.html 在本文中,我将解释命令模式,以及如何利用基于命令模式的第三方库来实现它们,以及如何 ...

  3. 介绍一个好用的工具类库commons-beanutils

    commons-beanutils.jar可以到Apache官网的commons子项目下找到它,或者,在Struts2,Spring的下载包中也能看到它的影子.单独使用时,要多引进一个commons- ...

  4. 推荐一个有用的Excel操作类库 LinqToExcel

    GitHub: LinqToExcel 以前项目中对Excel进行信息读取,我都是使用的NPOI的封装类,给定一个fileurl,然后返回给我一个datatable.接下去自己去解析数据.如果使用这种 ...

  5. 一个低调的王者 - 谁是游戏类Dapp圈内最赚钱的团队?

    Dapp作为曾经的风口,吸引着大批开发者前来淘金,然而2年来大浪淘沙,最后坚持下来的团队寥寥无几.今天要和大家介绍的这支团队算得上是Dapp圈的老炮儿了,开发的三款Dapp箭无虚发,从以太传奇到TRO ...

  6. 手写一个promise用法_手写一个自己的 JavaScript Promise 类库

    终于有时间写这篇文章了, ES2015 推出了JS 的 Promise ,而在没有原生支持的时候,我们也可以使用诸如 Promises/A+ 的库的帮助,在我们的代码里实现Promise 的支持: 如 ...

  7. 一个C#读写Dxf的类库DXFLibrary

    https://github.com/Titifonky/DXFLibrary DXF 参考手册: http://docs.autodesk.com/ACD/2011/CHS/filesDXF/WSf ...

  8. 用html 做一个低调的邮箱名片

    一.效果如下 简约大气 颜色可自由调整 二.源码 <!DOCTYPE html> <html><body align="center">< ...

  9. 一个低调Net程序员的2014年度总结

    回顾这一年,有些恍恍惚惚,脾气没变,生活依然是老样子,两点一线的生活不曾有过变动,在哈尔滨这个技术氛围不强城市,挣扎的活着. 一.工作中 14年初作为上一家公司最后一名Net程序员,哥们我离职了,用最 ...

最新文章

  1. 从Netflix的Hystrix框架理解服务熔断和服务降级
  2. 一个软件网络连接异常_手机也能玩PC大作了,串流软件Steam Link登陆iOS App Store...
  3. VC环境下的静态库(lib)使用和动态库(Dll)的使用(清晰版)
  4. java 6大原则_java 6大设计原则 一:观察者模式
  5. html5_canvas初学
  6. win与Linux的防火墙配置
  7. Element-UI-简单组合效果---Element-UI工作笔记002
  8. spring纯注解+libreoffice
  9. 英文字母对应的Unicode编码
  10. Leetcode 颜色分类
  11. AWS、Azure、谷歌云、阿里云最新全方位比较
  12. 设置word中第一页不显示页码,第二页页码从1开始
  13. QMediaplayer详解以及简易音乐播放实现
  14. 本周推荐 | JDK 11 升级实践 和 Java 新特性浅探
  15. 三、常规Dos命令附图
  16. 用jquery获取tbody下的第一个tr的最后一个td里面的第一个a标签
  17. 【台达 PLC - 0】 - 电气基础
  18. python文本情感分析:SnowNLP的应用---案例
  19. pyqt5做了一个无线网连接器,与君共勉
  20. win10网络图标变地球

热门文章

  1. 3、AngularJS2 架构
  2. .NET WinForm程序中给DataGridView表头添加下拉列表实现数据过滤
  3. FirewallD is not running
  4. 面向对象技术——UML
  5. 【转载】可复用的FS
  6. proftpd的配置
  7. 看看这套WPF开源基础控件库:WPFDevelopers
  8. winform进度条实现
  9. 基于事件驱动架构构建微服务第2部分:领域对象和业务规则
  10. 打造史上最小尺寸.Net Core单文件应用程序