中介者模式是一種常見的設計模式,旨再降低程序的耦合性,因為傳統的三層模式層層之間需要顯示的調用,必須上層依賴下層,耦合性很高,為了解耦,將所有的指令單獨放在一個位置處理,其他位置均通過這個位置來間接的調用,從而減少耦合,具體的可以參考中介者模式,建議先了解下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
