前言
簡單整理一下Mediator。
正文
Mediator 名字是中介者的意思。
那麼它和中介者模式有什麼關係呢?前面整理設計模式的時候,並沒有去介紹具體的中介者模式的程式碼實現。
如下:
https://www.cnblogs.com/aoximin/p/13600464.html
之所以沒寫程式碼就是因為它現在是一種思想,以前的簡單的已經很難滿足我們現在開發的需求了。
那麼看下Mediator 是如何做的吧。
Mediator 這個服務,是如何讓我們的命令查詢職責分離的。
首先安裝一下包:
Mediator 核心介面為:
-
IMediator
-
IRequest,IRequest
-
IRequestHandler<in IRequest,TResponse>
一般從介面就能看到其設計思想,其餘的實現,各有各的想法,那麼就來看下IMediator吧。
/// <summary>
/// Defines a mediator to encapsulate request/response and publishing interaction patterns
/// </summary>
public interface IMediator : ISender, IPublisher
{
}
這個介面的作用是定義了一箇中介者,這個中介者用來裝入請求或者響應和實現一些互動模式。
那麼看來分別就是ISender和IPublisher來實現了。
看下ISender:
/// <summary>
/// Send a request through the mediator pipeline to be handled by a single handler.
/// </summary>
public interface ISender
{
/// <summary>
/// Asynchronously send a request to a single handler
/// </summary>
/// <typeparam name="TResponse">Response type</typeparam>
/// <param name="request">Request object</param>
/// <param name="cancellationToken">Optional cancellation token</param>
/// <returns>A task that represents the send operation. The task result contains the handler response</returns>
Task<TResponse> Send<TResponse>(IRequest<TResponse> request, CancellationToken cancellationToken = default);
/// <summary>
/// Asynchronously send an object request to a single handler via dynamic dispatch
/// </summary>
/// <param name="request">Request object</param>
/// <param name="cancellationToken">Optional cancellation token</param>
/// <returns>A task that represents the send operation. The task result contains the type erased handler response</returns>
Task<object?> Send(object request, CancellationToken cancellationToken = default);
}
這個介面用來通過由單個處理程式的中介者管道中傳送請求。
IPublisher:
/// <summary>
/// Publish a notification or event through the mediator pipeline to be handled by multiple handlers.
/// </summary>
public interface IPublisher
{
/// <summary>
/// Asynchronously send a notification to multiple handlers
/// </summary>
/// <param name="notification">Notification object</param>
/// <param name="cancellationToken">Optional cancellation token</param>
/// <returns>A task that represents the publish operation.</returns>
Task Publish(object notification, CancellationToken cancellationToken = default);
/// <summary>
/// Asynchronously send a notification to multiple handlers
/// </summary>
/// <param name="notification">Notification object</param>
/// <param name="cancellationToken">Optional cancellation token</param>
/// <returns>A task that represents the publish operation.</returns>
Task Publish<TNotification>(TNotification notification, CancellationToken cancellationToken = default)
where TNotification : INotification;
}
這個介面用來通過多個處理程式的中介者管道中傳送通知或者事件。
好了,現在我們得到的資訊有"釋出"、"事件"、"請求"、"管道" 這幾個名詞了。
那麼實際上我們也能大致的猜出它是怎麼實現的。
接下來檢視IRequest:
/// <summary>
/// Marker interface to represent a request with a void response
/// </summary>
public interface IRequest : IRequest<Unit> { }
/// <summary>
/// Marker interface to represent a request with a response
/// </summary>
/// <typeparam name="TResponse">Response type</typeparam>
public interface IRequest<out TResponse> : IBaseRequest { }
/// <summary>
/// Allows for generic type constraints of objects implementing IRequest or IRequest{TResponse}
/// </summary>
public interface IBaseRequest { }
這些上面的英文已經提示了,標誌性作用,用來做定義的。
最後來看下IRequestHandler介面:
/// <summary>
/// Defines a handler for a request
/// </summary>
/// <typeparam name="TRequest">The type of request being handled</typeparam>
/// <typeparam name="TResponse">The type of response from the handler</typeparam>
public interface IRequestHandler<in TRequest, TResponse>
where TRequest : IRequest<TResponse>
{
/// <summary>
/// Handles a request
/// </summary>
/// <param name="request">The request</param>
/// <param name="cancellationToken">Cancellation token</param>
/// <returns>Response from the request</returns>
Task<TResponse> Handle(TRequest request, CancellationToken cancellationToken);
}
現在我們在來整理一下名詞:"釋出"、"事件"、"請求"、"管道" 、"處理請求"
那麼大概猜測大概通過介面來處理請求,然後還可以釋出事件處理的。處理請求有處理請求的管道,且這個處理是單個處理程式,而處理事件是多個處理程式。
接下來操作一遍:
async static Task Main(string[] args)
{
var services = new ServiceCollection();
services.AddMediatR(typeof(Program).Assembly);
var serviceProvider = services.BuildServiceProvider();
var mediator = serviceProvider.GetService<IMediator>();
await mediator.Send(new SelfCommand{ CommandName ="zhangsan"});
}
internal class SelfCommand : IRequest<long>
{
public string CommandName { get; set; }
}
internal class SelfCommandHandler : IRequestHandler<SelfCommand, long>
{
public Task<long> Handle(SelfCommand request, CancellationToken cancellationToken)
{
Console.WriteLine($"處理 {nameof(SelfCommand)}請求:{request.CommandName}");
return Task.FromResult(10L);
}
}
這裡就有一個疑問了,為啥SelfCommandHandler會自動稱為處理程式?我們並沒有設定啊。
那麼就來看一下send在幹什麼吧:
public Task<TResponse> Send<TResponse>(IRequest<TResponse> request, CancellationToken cancellationToken = default)
{
if (request == null)
{
throw new ArgumentNullException(nameof(request));
}
var requestType = request.GetType();
var handler = (RequestHandlerWrapper<TResponse>)_requestHandlers.GetOrAdd(requestType,
t => (RequestHandlerBase)Activator.CreateInstance(typeof(RequestHandlerWrapperImpl<,>).MakeGenericType(requestType, typeof(TResponse))));
return handler.Handle(request, cancellationToken, _serviceFactory);
}
上面可以看到生成了一個handle,然後呼叫了Handle 方法。
然後進RequestHandlerWrapperImpl 檢視:
internal class RequestHandlerWrapperImpl<TRequest, TResponse> : RequestHandlerWrapper<TResponse>
where TRequest : IRequest<TResponse>
{
public override Task<object?> Handle(object request, CancellationToken cancellationToken,
ServiceFactory serviceFactory)
{
return Handle((IRequest<TResponse>)request, cancellationToken, serviceFactory)
.ContinueWith(t =>
{
if (t.IsFaulted)
{
ExceptionDispatchInfo.Capture(t.Exception.InnerException).Throw();
}
return (object?)t.Result;
}, cancellationToken);
}
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))();
}
}
這裡埋一個坑,因為看了一下,有很多細節的地方比如說Activator.CreateInstance的機制、一些管道細節,還設計到註冊IPipelineBehavior<TRequest, TResponse>的實現類的機制,整理到該系列的細節篇中,將會比較詳細的介紹。
現在只需要看Handle的ContinueWith,如果失敗的話,那麼會返回一個異常,否則返回結果。
然後根據上面的,我們指定Request對應的RequstHandle 必須名字有如下規律:如SelfCommand,只需要SelfCommand加長一些即可,比如說SelfCommandHandler,比如說SelfCommandHandlerV2,還可以SelfCommand2都行。
但是呢,最好改好名字,後面加Handle。
同時,如果我們寫兩個SelfCommandHandler和SelfCommandHandlerV2,那麼是否兩個都會執行?不是的,只會執行一個。
internal class SelfCommandHandler2 : IRequestHandler<SelfCommand, long>
{
public Task<long> Handle(SelfCommand request, CancellationToken cancellationToken)
{
Console.WriteLine($"處理 {nameof(SelfCommand)} V2請求:{request.CommandName}");
return Task.FromResult(10L);
}
}
internal class SelfCommandHandler : IRequestHandler<SelfCommand, long>
{
public Task<long> Handle(SelfCommand request, CancellationToken cancellationToken)
{
Console.WriteLine($"處理 {nameof(SelfCommand)}請求:{request.CommandName}");
return Task.FromResult(10L);
}
}
比如說這樣,那麼會執行。
也就是說會執行SelfCommandHandler2。
那麼請求就算介紹完了,那麼看下事件。
呼叫事件這樣呼叫即可:
await mediator.Publish(new SelfEvent { EventName = "SelfEvent" });
具體類:
internal class SelfEvent : INotification
{
public string EventName { get; set; }
}
internal class SelfEventHandler : INotificationHandler<SelfEvent>
{
public Task Handle(SelfEvent notification, CancellationToken cancellationToken)
{
Console.WriteLine($"SelfEventHandler 執行:{notification.EventName}");
return Task.CompletedTask;
}
}
internal class SelfEventHandlerV2 : INotificationHandler<SelfEvent>
{
public Task Handle(SelfEvent notification, CancellationToken cancellationToken)
{
Console.WriteLine($"SelfEventHandlerV2 執行:{notification.EventName}");
return Task.CompletedTask;
}
}
效果:
那麼和requst不同的是,註冊幾個就會呼叫幾個。
好了現在回到中介者模式中來。
中介者模式(Mediator Pattern)是用來降低多個物件和類之間的通訊複雜性。這種模式提供了一箇中介類,該類通常處理不同類之間的通訊,並支援鬆耦合,使程式碼易於維護。中介者模式屬於行為型模式。
那麼Mediator 這個模組呢,幫助我們解決了request和requesthandle之間的耦合,和 Event與EventHandle 之間的耦合。
一開始我認為是命令模式,後來一想,命令模式解決“行為請求者”與“行為實現者”的耦合。
命令模式如下:
https://www.cnblogs.com/aoximin/p/13616558.html
上面只是命令模式的一種形式哈。
結
下一節領域事件的處理。以上只是個人整理,如有錯誤,望請指點。