MEDIATR 一个低调的中介者类库
微軟官方的開源項(xiàng)目eShopOnContainers中,用到了一個(gè)實(shí)現(xiàn)中介者模式的類庫:MediatR。這個(gè)類庫的作者叫Jimmy Bogard,在其gtihub主頁上可以看到,注明的對(duì)象映射組件AutoMapper?就是他寫的。其博客上的自我介紹是這么寫的:
Headspring的首席架構(gòu)師,《MVC in Action》的作者,國際演說家,高產(chǎn)的開源軟件開發(fā)者。擅長分布式系統(tǒng),REST,消息,領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)和CQRS。
回到MediatR這個(gè)組件,他是一個(gè)低調(diào)的類庫,致力于解決一個(gè)簡單的問題:解耦進(jìn)程內(nèi)消息的發(fā)送與處理??缙脚_(tái),支持.NET4.5和netstandard1.1。
中介者模式
在繼續(xù)研究MediatR之前,先回顧下“中介者設(shè)計(jì)模式(Mediator)”,中介者模式的定義為:用一個(gè)中介對(duì)象來封裝一系列的對(duì)象交互。中介者使各對(duì)象不需要顯式地相互應(yīng)用,從而使其耦合松散,而且可以獨(dú)立地改變他們之間的交互。其結(jié)構(gòu)圖如下:
以下是一個(gè)具體的中介者模式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> /// 具體中介者,負(fù)責(zé)同事類之間的交互,他必須清楚的知道需要交互的所有同事類的細(xì)節(jié)。 /// </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,他是不知道其他具體同事類的存在的。他與其他同事類的交互,是通過中介者來實(shí)現(xiàn)的。 /// </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>/// 客戶端調(diào)用/// </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,好的。
中介者類把不同的同事類之間的交互提升到其內(nèi)部,這樣同事類之間的交互變得簡單了,同事類不需要知道其他同事類的存在,通過中介者類來完成與其他同事類的交互。另一方面,中介者類本身復(fù)雜性增加,中介者類需要知道所有的同事類,例如調(diào)用他們的公共方法。
MediatR
MediatR可以與很多依賴注入組件一起工作,其github文檔有詳細(xì)說明。以下是我結(jié)合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可以支持幾種模式,有請(qǐng)求/響應(yīng)模式,發(fā)布模式。
請(qǐng)求/響應(yīng)模式,也可以叫做命令模式,主要適用于命令和查詢場(chǎng)景。一個(gè)請(qǐng)求只能被一個(gè)處理者捕獲,如果存在多個(gè)處理者,那么只有最后一個(gè)處理者會(huì)被激活。
以下代碼聲明消息,然后定義處理者:
/*注意:請(qǐng)求/響應(yīng)接口適用于命令和查詢場(chǎng)景。*都只能有一個(gè)Handler,如果注冊(cè)多個(gè),只有最后一個(gè)會(huì)生效。*/ 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";} }然后就是發(fā)送請(qǐng)求了:
var response = await mediator.Send(new Ping(){MsgId = 100}); Console.WriteLine(response); // "SyncHandler Pong"
另外,請(qǐng)求/響應(yīng)模式還支持不帶任何返回值的處理者:
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;} }
發(fā)布模式,一般用于發(fā)布一個(gè)事件,通知訂閱者某件事情已經(jīng)發(fā)生,對(duì)此事感興趣的訂閱者可以采取行動(dòng)了。一般是一個(gè)發(fā)布這,多個(gè)訂閱者。
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}");} }
像這樣發(fā)布消息:
await mediator.Publish(new Hello() {MsgId = 300});
程序輸出如下:
300,4 300,5 Main 5
這里可以看到,2個(gè)訂閱者都被激活了。另外,可以看到不同的訂閱者所處的線程ID不一樣,他們是異步執(zhí)行的。
原文地址?:http://coderyu.com/2018/04/02/mediatr-%E4%B8%AD%E4%BB%8B%E8%80%85/
.NET社區(qū)新聞,深度好文,歡迎訪問公眾號(hào)文章匯總 http://www.csharpkit.com
總結(jié)
以上是生活随笔為你收集整理的MEDIATR 一个低调的中介者类库的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 微软发布自己定制的 Linux 内核和发
- 下一篇: ApacheSkyWalking APM