中介者设计模式-Mediator
随着微服务的流行,而DDD(领域驱动设计)也光速般兴起,CRQS(Command Query Responsibility Seperation--命令查询职责分离)、领域事件名词是不是经常在耳边环绕,而MediatR组件经常用来对其技术的落地,凭这,小伙伴们说火不火?(强行引入主题,牛掰不!!!);但是今天不说微服务,也不说DDD,只说MediatR的使用,哈哈哈,开始吧;
![](https://pic1.zhimg.com/80/v2-2affc2daf199bf3305f1e50038799068_1440w.webp)
正文
![](https://pic3.zhimg.com/80/v2-075db2e1834719c80f973c3621848742_1440w.webp)
二话不说就上图,图中大概意思就是说:MediatR是用.Net实现的简单中介者模式,无需其他依赖就能处理进程内的消息传递,支持请求/响应、命令、查询、通知和事件的同步或异步传递,通过C#的泛型智能调度。
开源地址:https://github.com/jbogard/MediatR
Mediator有两种消息调度方式:
- Request/Response(请求/响应)消息,只能单个处理程序处理;
一个请求/响应消息由一个消息处理程序进行处理;通过实现IRequest接口来抽象请求/响应消息,实现IRequestHandler来进行消息处理;
- Notification(通知)消息,可以由多个处理程序处理;
一个通知消息由多个消息处理程序进行处理;通过实现INotification接口来抽象通知消息,实现INotificationHandler来进行消息处理;
刚才说到,MediatR组件实现了简单的中介者模式,刚好逮住机会说说中介者设计模式;
中介者模式(Mediator):用一个中介对象来封装一系列的对象交互。中介者使各对象不需要显示地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互
大话设计模式
结构如下图(图来源于大话设计模式):
![](https://pic3.zhimg.com/80/v2-60549a35f1902c875ed4ccc4514c9bda_1440w.webp)
上面是不是有点专业,咱们找个生活中例子,比如房产中介,先假如没有房产中介这个中间对象时,卖房者和买房者之间都是互相关联,耦合在一起,卖房者之间可以互相推荐找优质房源给买房者,买房者之间也能互相分享好的房源,自己不适合,朋友或者亲戚可能适合,如下图:
![](https://pic1.zhimg.com/80/v2-aa7da5ae6d8da3a9745c55f2eab3d15c_1440w.webp)
上图看上去是不是显得每个人都很忙,而且需要对接不同的人,电话和信息肯定少不了,那是不是就没时间干其他的了,比如上班、陪孩、约会这些咋可能少嘛,对不对;有了房屋中介之后,看下图:
![](https://pic1.zhimg.com/80/v2-a426805a4ba38427d5f7da7e66d7877c_1440w.webp)
这样看着是不是比较清晰了,卖房找中介,买房找中介,通过中介统一分享信息,这样就忙房屋中介即可(人家专业,就是干这行的),其余每个人,就和中介交互信息即可。
结合上面的结构图和案例,代码如下:
由于有多个房屋中介公司,这里先将其进行抽象出来,相当于结构图中Mediator:
![](https://pic1.zhimg.com/80/v2-8a9d013f4e793d09c192659698bce5c4_1440w.webp)
然后将卖房者和买房者进行抽象化,相当于结构图中的Colleague,如下:
![](https://pic3.zhimg.com/80/v2-95c681fd0353a401ce51effc1226976a_1440w.webp)
实现具体的卖房者和买房者,相当于结构图中的ConcreteColleague1、ConcreteColleague2,如下:
![](https://pic2.zhimg.com/80/v2-592d5041d2310ab3f79fe704ac39a029_1440w.webp)
实现具体的中介者,相当于结构图中的ConcreteMediator,如下图:
![](https://pic3.zhimg.com/80/v2-00679ef0f1b663c4714e4f5739c1a4c2_1440w.webp)
使用及运行效果如下:
![](https://pic1.zhimg.com/80/v2-b180f5da910125c573e691e0341f1500_1440w.webp)
由上可以明显感觉到中介者好处,各对象没有直接耦合,而是通过中介者进行各对象的连接,从原来的网状结构就变得相对单一;但具体的中介者的任务会因为ConcreteColleague的越来越多变得比较繁重,代码不容易维护,因为中介者需要了解所有ConcreteColleague对象操作; 以上买卖房的思想可能没有很好的体现各个ConcreteColleague交互,但如果换成房屋出租,感觉是不是稍微直接一点啦。
Mediator中介者模式就简单到这吧,回到文章主题MediatR组件,停!!!小伙伴会问:Mediator中介者和MediatR组件是不是哪个词写错了?如果指的是单词的话,MediatR不对,但从功能角度上看,MediatR不仅仅实现了Mediator中介者模式,而且加入了依赖注入,使得使用更加方便,这可能就是作者将其命名MediatR的原因吧。后续抽时间再和小伙伴们一起扒扒源代码,这里就先看看怎么使用,看看到底有多方便,先用控制台程序演示↓↓↓
请求/响应消息及其处理:
![](https://pic3.zhimg.com/80/v2-c51fb7b0bf63eed3a191877b512c7dd6_1440w.webp)
使用及运行如下图:
![](https://pic3.zhimg.com/80/v2-7140f9fb7264455a7ff570e4d2786abe_1440w.webp)
以上定义简单分为以下几步:
- 请求消息和请求消息处理类;
- 注册相关MediatR相关组件;
- 从容器中获取到中介者,通过中介者发送消息;
以上简单三步完成之后,对应消息类型的处理类就会自动处理,这就是据泛型智能处理对应消息功能。这些都是MediatR组件内部处理好,为小伙伴们减少创建对象、关联中介者、消息关联等操作。
请求/响应消息是一对一处理的,假如有多个处理怎么办呢?
![](https://pic1.zhimg.com/80/v2-2fb7a04746c0cf787d5e9dcb8f81b8d4_1440w.webp)
结论:当同一个类型请求/响应消息有多个处理类时,会根据扫描注册时进行覆盖,最终只有一个处理类生效。
应用场景:通常会用来实现CQRS(命令查询职责分离),也可以用于模块解耦相关场景。
注意:
- IRequest代表无返回值;
- IRequest代表有返回值,返回类型为T;
- IRequestHandler中RequestMsg指消息类,代表该处理类只能处理RequestMsg的消息,T代表返回类型;
通知消息及其处理
![](https://pic4.zhimg.com/80/v2-d12c72d71963c6b28c9a87a464bbbbab_1440w.webp)
使用及运行如下图:
![](https://pic3.zhimg.com/80/v2-c43f7468f0981e1e0d32673856e99de6_1440w.webp)
通知消息是支持多处理类处理的。
应用场景:领域事件的实现;也可以用于业务分离场景,比如用户注册成功之后,需要进行消息发送通知,有邮件、微信、短信等方式。
在WebAPI中使用MediatR,如下:
跟着图中步骤走:
![](https://pic3.zhimg.com/80/v2-036e79462de50bc8b51beb6d79c82efe_1440w.webp)
![](https://pic2.zhimg.com/80/v2-e55a5ea1be0f6bd966ae3f62a5c1027d_1440w.webp)
开始使用吧,走起:
![](https://pic4.zhimg.com/80/v2-0748b8e2b5385224e2d2666803d52f73_1440w.webp)
跑起来看看,一气呵成,哈哈哈:
![](https://pic2.zhimg.com/80/v2-f2c2c409071724f12efed7045a1119c1_1440w.webp)
通过以上Demo可以看到,控制器现在和业务没有直接关系,不需要再和业务层关联,通过一个中介者完成业务流程,显得控制器更加清晰,只负责提供接口、接收数据和权限标注。上面Demo为了演示都把新增用户的命令消息和新增成功的事件消息都放在一起,其实在实际开发中可以根据需要进行归类。
总结
好啦,MediatR的应用就先到这吧,后续单独抽时间整理一篇源码和小伙伴一起分享