一起来学习.net core程序使用中介者模式:MediatR插件
中介者模式是一种常见的设计模式,旨再降低程序的耦合性,因为传统的三层模式层层之间需要显示的调用,必须上层依赖下层,耦合性很高,为了解耦,将所有的指令单独放在一个位置处理,其他位置均通过这个位置来间接的调用,从而减少耦合,具体的可以参考中介者模式,建议先了解下DDD里面的事件总线和命令分发。
实现中介者模式有很多方式,例如MediatR就是一种很好用的插件,作者的介绍是这样说的“.NET中的简单中介实现,没有依赖关系的进程内消息传递。通过C#泛型方差支持请求/响应,命令,查询,通知和事件,同步和异步与智能调度。”。这里推荐一款插件Dnspy可以查看dll的源码,这样就可以知道我们所使用的的插件的原理了。
这里先建好一个.Net Core程序,。然后程序入口处注入MeditaR
services.AddMediatR(typeof(Startup));
//注册发布订阅中介处理
services.AddScoped<IMediatorHandler,MediatorHandler>();
services.AddScoped<IRequestHandler<CreateUserCommand, Unit>, UserCommandHandler>();
对于中介,肯定要先做一个中介处理器,因为程序是面向接口的,所以先定义一个接口,用来表示中介处理器
/// <summary> /// 中介处理接口 /// </summary> public interface IMediatorHandler { /// <summary> /// 发送领域事件 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="command"></param> /// <returns></returns> Task SendCommand<T>(T command) where T :Command; }
然后就是它的实现类
public class MediatorHandler: IMediatorHandler { private readonly IMediator _mediator; public InMemoryBus(IMediator mediator) { _mediator = mediator; } /// <summary> /// 发送邻域事件 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="command"></param> /// <returns></returns> public Task SendCommand<T>(T command) where T : Command { try { return _mediator.Send(command); } catch (AggregateException ex) { throw ex; } } }
这里我们用到了IMediator,我们可以根据Dnspy这个工具查看到IMediator 的Send的方法的实现,
// MediatR.Mediator // Token: 0x06000018 RID: 24 RVA: 0x00002100 File Offset: 0x00000300 public Task<TResponse> Send<TResponse>(IRequest<TResponse> request, CancellationToken cancellationToken = default(CancellationToken)) { if (request == null) { throw new ArgumentNullException("request"); } Type requestType = request.GetType(); return ((RequestHandlerWrapper<TResponse>)Mediator._requestHandlers.GetOrAdd(requestType, (Type t) => Activator.CreateInstance(typeof(RequestHandlerWrapperImpl<, >).MakeGenericType(new Type[] { requestType, typeof(TResponse) })))).Handle(request, cancellationToken, this._serviceFactory); }
首先我们看到它的参数IRequest<TResponse> request,所以我们可以知道Task SendCommand<T>(T command),这个方法的T一定是继层自IRequest,所以需要我们写一个基类继层于IRequest
/// <summary> /// 领域命令基类 /// </summary> public class Command:IRequest { } /// <summary> /// 创建用户领域命令 /// </summary> public class CreateUserCommand: Command { public CreateUserCommand(User user) { User = user; } public User User { get; private set; } }
因为项目需要添加功能,好比注册一个用户,所以有一个添加用户的Service代码,然后在构造函数里注入IMediatorHandler
public class UserService :IUserService { private readonly IUserRepository _userRepository; private readonly IMediatorHandler _mediatorHandler; public UserService(IUserRepository userRepository, IMediatorHandler mediatorHandler) { _userRepository = userRepository; _mediatorHandler = mediatorHandler; } public void Insert(User user) { var command = new CreateUserCommand(user); try { Task task = _mediatorHandler.SendCommand(command); Task.WaitAll(task); } catch (AggregateException) { throw new FrameworkException("程序内部错误"); } } }
public class UserCommandHandler : IRequestHandler<CreateUserCommand, Unit> { private readonly IUserRepository _userRepository; private readonly IMediatorHandler _mediatorHandler; public UserCommandHandler(IUserRepository userRepository, IMediatorHandler mediatorHandler) { _userRepository = userRepository; _mediatorHandler = mediatorHandler; } public Task<Unit> Handle(CreateUserCommand command, CancellationToken cancellationToken) { _userRepository.Insert(command.User); return Task.FromResult(new Unit()); } }
到这里可以说已经完成了,可以执行了,这样的例子网上也有很多。但是还是需要去了解它的源码,但是自己目前自己只是读懂了源码的20%左右,根据我的理解就是我们在调用IMediator的Send方法时,线程安全集合_requestHandlers会把我们的请求添加到内存里面,具体的就是CreateInstance一个RequestHandlerWrapperImpl对象,但是通过MakeGenericType把它的类型变成了我们请求的类型和返回的类型,然后通过(RequestHandlerWrapper<TResponse>)将Mediator转换类型调用Handler,继续执行RequestHandlerWrapper的实现类RequestHandlerWrapperImpl,然后通过某种方式调用了IRequestHandler,然后找到IRequestHandler的实现类UserCommandHandler,从而完成添加功能。
无奈自己才疏学浅,并没有理解作者的意思。我现在还是有很多疑问。
,以下是我自认为比较重要的的位置了:
1 ,这个类我删了很多代码,只留了我们用的到的 Send方法MediatorHandler类里面用到的
public class Mediator : IMediator { // Token: 0x06000017 RID: 23 RVA: 0x000020F1 File Offset: 0x000002F1 public Mediator(ServiceFactory serviceFactory) { this._serviceFactory = serviceFactory; } // Token: 0x06000018 RID: 24 RVA: 0x00002100 File Offset: 0x00000300 public Task<TResponse> Send<TResponse>(IRequest<TResponse> request, CancellationToken cancellationToken = default(CancellationToken)) { if (request == null) { throw new ArgumentNullException("request"); } Type requestType = request.GetType(); return ((RequestHandlerWrapper<TResponse>)Mediator._requestHandlers.GetOrAdd(requestType, (Type t) => Activator.CreateInstance(typeof(RequestHandlerWrapperImpl<, >).MakeGenericType(new Type[] { requestType, typeof(TResponse) })))).Handle(request, cancellationToken, this._serviceFactory); } // Token: 0x04000001 RID: 1 private readonly ServiceFactory _serviceFactory; // Token: 0x04000002 RID: 2 private static readonly ConcurrentDictionary<Type, object> _requestHandlers = new ConcurrentDictionary<Type, object>(); }
2,
public interface IPipelineBehavior<in TRequest, TResponse> { // Token: 0x0600000C RID: 12 Task<TResponse> Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate<TResponse> next); }
3
internal abstract class RequestHandlerWrapper<TResponse> : RequestHandlerBase { public abstract Task<TResponse> Handle(IRequest<TResponse> request, CancellationToken cancellationToken, ServiceFactory serviceFactory); } internal class RequestHandlerWrapperImpl<TRequest, TResponse> : RequestHandlerWrapper<TResponse> where TRequest : IRequest<TResponse> { public override Task<TResponse> Handle(IRequest<TResponse> request, CancellationToken cancellationToken, ServiceFactory serviceFactory) { Task<TResponse> Handler() => GetHandler<IRequestHandler<TRequest, TResponse>>(serviceFactory).Handle((TRequest) request, cancellationToken); return serviceFactory .GetInstances<IPipelineBehavior<TRequest, TResponse>>() .Reverse() .Aggregate((RequestHandlerDelegate<TResponse>) Handler, (next, pipeline) => () => pipeline.Handle((TRequest)request, cancellationToken, next))(); } }
4,
public abstract class RequestHandler<TRequest> : IRequestHandler<TRequest>, IRequestHandler<TRequest, Unit> where TRequest : IRequest { // Token: 0x06000014 RID: 20 RVA: 0x000020DB File Offset: 0x000002DB Task<Unit> IRequestHandler<TRequest, Unit>.Handle(TRequest request, CancellationToken cancellationToken) { this.Handle(request); return Unit.Task; } // Token: 0x06000015 RID: 21 protected abstract void Handle(TRequest request); }
4
- 学习实践:使用模式,原则实现一个C++自动化测试程序
- 学习实践:使用模式,原则实现一个C++自动化测试程序
- java学习之旅15、16--eclipse开发环境的使用_建立java项目_运行java项目,eclipse运行程序的问题(src和bin问题)_debug模式
- 学习实践:使用模式,原则实现一个C++自动化测试程序
- 十一个行为型模式5:中介者模式-Mediator Pattern【学习难度:★★★☆☆,使用频率:★★☆☆☆】
- [译]ASP.NET Core中使用MediatR实现命令和中介者模式
- CSharp设计模式读书笔记(18):中介者模式(学习难度:★★★☆☆,使用频率:★★☆☆☆)
- 在 ASP.NET Core 项目中使用 MediatR 实现中介者模式
- 使用设计模式改善程序结构(二)
- Ext JS 学习(5) Ext.FormPanel 组件的使用第二式(fieldset的使用, ExtJS表单验证模式)
- 在jsp程序中使用com组件(资料学习)
- C#面向对象设计模式纵横谈 学习笔记17 Mediator 中介者模式(行为型模式)
- 使用设计模式改善程序结构(一)
- winform程序中使用document-view模式的考虑
- 使用接口实现附带插件功能的程序
- 使用设计模式改善程序结构(一)
- JSP设计模式基础:View Helper模式——学习如何使用View Helper模式使得Model数据适应表现层的需要(3)
- 插件架构学习体会(二) -- 插件程序说:要求平等对话
- lighttpd学习–使用mod_secdownload模块防盗链及fastcgi模式配置 ZT
- [笔记].在Quartus II中使用JTAG模式固化程序到EPCS中的方法