MediatR 何时以及为什么要使用它?

110

这个问题可能已经有人问过了,但我在官网上找不到为什么我应该使用MediatR以及它解决了哪些问题?

  • 是因为我可以通过构造函数传递单个对象而不是众多接口吗?

  • 它是ServicesBus的替代品或竞争对手吗?

  • 基本上,它有什么好处和解决了什么问题?

我想采用它,但我不清楚我为什么要使用它。

非常感谢


4
在这里扮演魔鬼的代言人,是一篇关于为什么在将其引入项目之前需要三思而后行的帖子 - https://alex-klaus.com/mediator/ - Alex Klaus
2个回答

117

是因为我可以在构造函数中传递单个对象而不是多种接口吗?

不是。

它是ServicesBus的替代品或竞争对手吗...

不是。

基本上有哪些好处,以及它解决了什么问题


除其他问题外,MediatR试图解决的一个问题是在您的MVC控制器中的DI构造函数爆炸

public DashboardController(
    ICustomerRepository customerRepository,
    IOrderService orderService,
    ICustomerHistoryRepository historyRepository,
    IOrderRepository orderRepository,
    IProductRespoitory productRespoitory,
    IRelatedProductsRepository relatedProductsRepository,
    ISupportService supportService,
    ILog logger
    )  

这是一个备受争议的话题,没有一种通用解决方案,看一下这个问题:

如何避免依赖注入构造函数的混乱?

如果你想在更多的抽象层面上隐藏依赖关系,那么此时你需要查看所有选项,比如重构,更进一步地分离关注点或其他技术。

说实话,MediatR 网站上给出的示例问题和解决方案有点可疑,但它确实有其用处。简而言之,你需要选择适合你和你的环境的内容。

中介者模式概述

中介者是一个对象,它决定对象如何以及何时相互交互。它封装了“如何”并基于状态、调用方式或提供给它的负载协调执行。

至于你问题的本质,你应该真正看一下这个网站:

使用 MediatR 简化开发和分离关注点

MediatR是中介者模式的开源实现,它不试图做太多事情也不会施展魔法。它允许您使用同步或异步模式组合消息、创建和侦听事件。它有助于减少耦合并隔离请求工作和创建调度工作处理程序之间的关注点。
中介者模式通过中介者(一个东西)进行通信,帮助解耦应用程序。
通常,程序由大量类组成。然而,随着越来越多的类被添加到程序中,这些类之间的通信问题可能变得更加复杂。这使得程序更难阅读和维护。此外,更改程序可能变得困难,因为任何更改都可能影响其他几个类中的代码。
使用中介者模式,对象之间的通信封装在中介者对象内部。对象不再直接相互通信(解耦),而是通过中介者进行通信。这减少了通信对象之间的依赖性,从而减少了耦合。
在现代软件中,中介者模式通常在许多框架中找到,但您可以创建自己的中介者模式,或者使用其中许多可用的模式。
从这里开始,我认为你应该做更多的研究,我是说通常在研究之前你会发现你需要这些东西,然而在这种情况下,我认为你真的需要找一些好的例子来知道你是否想要中介者模式,甚至更多的是MediatR库。
更新 wired_in对此进行了实际的评论
所有MediatR所做的就是为请求服务定位处理程序。这不是中介者模式。在这种情况下,“中介者”并没有描述两个对象如何通信,它使用了已经在应用程序中使用的控制反转,只提供了一个无用的抽象层,使整个应用程序更难以理解。通过使用IoC的标准构造函数注入,您已经实现了解耦合。我不明白为什么人们会接受这个观点。让我们创建多个复合根,这样我们就不必在构造函数中放置接口。

OP完全有理由质疑MediatR的意义。我听到的对问题的最高回答包括解释中介者模式的使用,或者它使调用代码更清晰。前者的解释假定MediatR库实际上实现了中介者模式,这一点远非明显。后者不是在已经抽象化的IoC容器上添加另一个抽象化的理由,这会创建多个复合根。只需注入处理程序而不是服务定位它。

2
谢谢您的回复。我正在尝试学习MediatR,为什么会有人踩我,我不明白。 - developer9969
3
因为这是一个相当主观的问题,非常广泛,任何潜在的获胜答案都只是你最喜欢的答案。 - TheGeneral
52
MediatR只是为请求定位处理程序。这并不是中介者模式。在这种情况下, "中介者"并不描述两个对象如何通信,它使用了应用程序已经使用的控制反转,并提供了一个无用的抽象层,只会使整个应用程序更难以理解。通过使用IoC和标准构造函数注入,您已经实现了解耦合。我不明白为什么人们会相信这个。让我们创建多个复合根,这样我们就不必在构造函数中放置接口。 - wired_in
21
OP 对于质疑 MediatR 的用途完全是有道理的。我听到的对这个问题的头号回应通常涉及解释中介者模式的使用,或者称其能使调用代码更加简洁。前者的解释假定 MediatR 库实际上实现了中介者模式,这点远非明确。后者不足以证明在已经抽象化的 IoC 容器之上再添加另一个抽象层级的必要性,这会导致多个组合根源。相比于服务位置定位,直接注入处理程序即可。 - wired_in
4
我偶然看到了这篇文章,希望能够得到一个使用这种方法的优缺点清单,以便我不必自己编写。很遗憾,这篇回答被接受了,但它未能回答问题。评论中过于强调问题是有争议的。问题主要在于被接受的答案,而不是问题本身。问题是否措辞更好?是的,但最终问题是询问 MediatR 试图解决哪些问题。它肯定有一个客观目的。它也有优缺点。最好忽略意见部分,即优劣势如何。 - Derek Greer
显示剩余13条评论

17

它只是一种在业务逻辑组件之间实现通信的方式。

想象一下你有:

FirstRequest // which handled by FirstRequestHandler(FirstRequest)
SecondRequest // which handled by SecondRequestHandler(SecondRequest)
ThirdRequest // which handled by ThirdRequestHandler(ThirdRequest)

......有数百个……

接下来是ComplexRequest,当需要将FirstResponse和ThirdResponse组合成ComplexResponse时。

我们该如何解决这个问题?

嗯,ComplexRequestHandler将不得不注入FirstHandler和ThirdHandler,获取它们的结果,并将它们组合起来。

但为什么ComplexRequestHandler应该访问FirstRequestHandler接口呢? 为什么我们要麻烦地注入First、Third...OneHundredAndTwentythHandler到我们的ComplexHandler中呢?

在这种情况下,MediatR为我们提供了一个第三方,告诉我们:"给我一个请求,我会给你正确的响应,相信我!"

因此,ComplexHandler并不知道任何关于First和Third Handlers的信息。 它只知道所需的请求和响应(通常只是包装DTOs)。

注:您不一定要使用MediatR库。您可以阅读有关Mediator模式并自己实现它。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接