天天看點

重新整理 .net core 實踐篇—————Mediator實踐[二十八]

前言

簡單整理一下Mediator。

正文

Mediator 名字是中介者的意思。

那麼它和中介者模式有什麼關系呢?前面整理設計模式的時候,并沒有去介紹具體的中介者模式的代碼實作。

如下:

https://www.cnblogs.com/aoximin/p/13600464.html

之是以沒寫代碼就是因為它現在是一種思想,以前的簡單的已經很難滿足我們現在開發的需求了。

那麼看下Mediator 是如何做的吧。

Mediator 這個服務,是如何讓我們的指令查詢職責分離的。

首先安裝一下包:

重新整理 .net core 實踐篇—————Mediator實踐[二十八]

Mediator 核心接口為:

  1. IMediator
  2. IRequest,IRequest
  3. 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);
	}
}
           
重新整理 .net core 實踐篇—————Mediator實踐[二十八]

這裡就有一個疑問了,為啥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);
	}
}
           

比如說這樣,那麼會執行。

重新整理 .net core 實踐篇—————Mediator實踐[二十八]

也就是說會執行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;
	}
}
           

效果:

重新整理 .net core 實踐篇—————Mediator實踐[二十八]

那麼和requst不同的是,注冊幾個就會調用幾個。

好了現在回到中介者模式中來。

中介者模式(Mediator Pattern)是用來降低多個對象和類之間的通信複雜性。這種模式提供了一個中介類,該類通常處理不同類之間的通信,并支援松耦合,使代碼易于維護。中介者模式屬于行為型模式。

那麼Mediator 這個子產品呢,幫助我們解決了request和requesthandle之間的耦合,和 Event與EventHandle 之間的耦合。

一開始我認為是指令模式,後來一想,指令模式解決“行為請求者”與“行為實作者”的耦合。

指令模式如下:

https://www.cnblogs.com/aoximin/p/13616558.html

上面隻是指令模式的一種形式哈。

下一節領域事件的處理。以上隻是個人整理,如有錯誤,望請指點。