做者:依樂祝
原文地址:http://www.javashuo.com/article/p-bwogrvhz-me.htmlhtml
在本文中,我將解釋命令模式,以及如何利用基於命令模式的第三方庫來實現它們,以及如何在ASP.NET Core中使用它來解決咱們的問題並使代碼簡潔。所以,咱們將經過下面的主題來進行相關的講解。數據庫
從根本上講,命令模式是一種數據驅動的設計模式,屬於行爲模式的範疇。命令是咱們能夠執行的某種操做或行爲,它能夠是活動的一部分。一個活動能夠有一個或多個命令和實現。c#
咱們能夠這樣來講,請求以命令的形式包裹在對象中,並傳給調用對象。調用者(代理)對象查找能夠處理該命令的合適的對象,並把該命令傳給相應的對象,該對象執行命令 。設計模式
一個簡單的例子是多種類型的消息。Message類包含SendEmail()和SendSms()等屬性和方法。使用兩種類型的命令,而且須要一個接口,它應該由實現了EmailMessageCommand和SMSMessageCommand的類類繼承。還使用代理類來調用特定類型的消息類來處理操做。架構
class Program { static void Main(string[] args) { Message message = new Message(); message.CustomMessage = "Welcome by Email"; EmailMessageCommand emailMessageCommand = new EmailMessageCommand(message); Message message2 = new Message(); message2.CustomMessage = "Welcome by SMS"; SmsMessageCommand smsMessageCommand = new SmsMessageCommand(message2); Broker broker = new Broker(); broker.SendMessage(emailMessageCommand); broker.SendMessage(smsMessageCommand); Console.ReadKey(); } }
public class Message { public string CustomMessage { get; set; } public void EmailMessage() { Console.WriteLine($"{CustomMessage} : Email Message sent"); } public void SmsMessage() { Console.WriteLine($"{CustomMessage} : Sms Message sent"); } }
public interface IMessageCommand { void DoAction(); } public class Broker { public void SendMessage(IMessageCommand command) { command.DoAction(); } }
public class EmailMessageCommand : IMessageCommand { private Message oMessage; public EmailMessageCommand(Message oMessage) { this.oMessage = oMessage; } public void DoAction() { oMessage.EmailMessage(); } } public class SmsMessageCommand : IMessageCommand { private Message oMessage; public SmsMessageCommand(Message oMessage) { this.oMessage = oMessage; } public void DoAction() { oMessage.SmsMessage(); } }
當咱們開始使用MVC框架進行開發時,邏輯是用控制器的動做方法編寫的;就像咱們有一個簡單的電子商務應用程序,其中用戶應該會下訂單。咱們有一個控制器,OrderController,用來管理訂單。當用戶下訂單時,咱們應該在數據庫中保存記錄。
在此以前,咱們有一個簡化的代碼。然而,通過一段時間後,咱們意識到還有一個確認電子郵件的業務需求。如今,第二步是發送確認電子郵件給客戶。後來,咱們意識到,在這個步驟以後,咱們還須要執行另外一個操做,即,記錄信息等。最後,咱們還須要將用戶的信息保存到CRM中。關鍵是它會增加控制器的大小。如今,咱們能夠稱之爲「臃腫控制器」。
基於命令的體系結構容許咱們發送命令來執行某些操做,而且咱們有單獨的命令處理程序,使關注點分離和提升單一職責。爲了實現這個架構,咱們可使用第三方庫,好比MediatR(Mediator.),它爲咱們作了不少基礎工做。中介模式定義了一個對象,該對象封裝了一組對象是如何交互的。框架
MediatR容許咱們經過讓控制器Action向處理程序發送請求消息來將控制器與業務邏輯解耦。MediatR庫支持兩種類型的操做。asp.net
咱們已經介紹了命令模式,所以是時候定義一些命令並使用MediatR發出命令了。函數
咱們須要從NuGet安裝MediatR和MediatR.Extensions.Microsoft.DependencyInjection包。this
當這兩個軟件包安裝完畢後,咱們須要添加services.AddMediatR(); 到startup.cs文件。看起來像這樣。.net
如今,咱們可使用.NET Core 項目中的MediatR了。
第一個示例演示了使用MediatR使用請求/響應類型的操做。它指望對請求作出一些反應。
第二個示例將向您展現一個事件,其中多個處理程序執行它們的工做,調用者並不關心接下來會發生什麼,也不指望任何結果/響應。
在這種場景下,咱們但願註冊用戶並指望對請求作出一些響應。若是響應返回true,咱們能夠像登陸用戶同樣進行進一步的操做。
首先,咱們須要建立一個繼承自IRequest
public class NewUser: IRequest<bool> { public string Username { get; set; } public string Password { get; set; } }
IRequest
如今,須要一個處理程序來處理這種類型的請求。
public class NewUserHandler : IRequestHandler<NewUser, bool> { public Task<bool> Handle(NewUser request, CancellationToken cancellationToken) { // save to database return Task.FromResult(true); } }
如今咱們有了命令和它的處理程序,咱們能夠調用MediatR在咱們的控制器中作一些操做。
這些是Home控制器的動做方法。
public class HomeController : Controller { private readonly IMediator _mediator; public HomeController(IMediator mediator) { _mediator = mediator; } [HttpGet] public ActionResult Register() { return View(); } [HttpPost] public ActionResult Register(NewUser user) { bool result = _mediator.Send(user).Result; if (result) return RedirectToAction("Login"); return View(); } }
註冊操做方法使用了[HttpPost]屬性進行修飾,並接受新的用戶註冊請求。而後,它請求MediatR 進行處理。它指望來自請求的結果/響應,若是結果是真的,則將用戶重定向到登陸頁面。
這裏,咱們有簡潔的代碼,大部分的工做是在控制器外部完成的。這實現了對不一樣操做的處理的關注點分離(SoC)和單一責任的分離。
在第二個示例中,咱們將演示使用多個處理程序對命令執行不一樣操做的場景。
在這種狀況下,咱們使NewUser 繼承了INotification
public class NewUser : INotification { public string Username { get; set; } public string Password { get; set; } }
如今,有三個處理程序逐個執行,以完成他們的工做。這些都是從INotificationHandler繼承下來的。
public class NewUserHandler : INotificationHandler<NewUser> { public Task Handle(NewUser notification, CancellationToken cancellationToken) { //Save to log Debug.WriteLine(" **** Save user in database *****"); return Task.FromResult(true); } }
第二個處理程序在下面的代碼中定義。
public class EmailHandler : INotificationHandler<NewUser> { public Task Handle(NewUser notification, CancellationToken cancellationToken) { //Send email Debug.WriteLine(" **** Email sent to user *****"); return Task.FromResult(true); } }
這是第三個處理程序的代碼
public class LogHandler : INotificationHandler<NewUser> { public Task Handle(NewUser notification, CancellationToken cancellationToken) { //Save to log Debug.WriteLine(" **** User save to log *****"); return Task.FromResult(true); } }
而後,咱們控制器中的代碼像下面這樣
public class AccountsController : Controller { private readonly IMediator _mediator; public AccountsController(IMediator mediator) { _mediator = mediator; } [HttpGet] public ActionResult Login() { return View(); } [HttpGet] public ActionResult Register() { return View(); } [HttpPost] public ActionResult Register(NewUser user) { _mediator.Publish(user); return RedirectToAction("Login"); } }
此應用程序的輸出以下:
當用戶註冊後,三個處理程序逐個執行——分別是NewUserHandler、EmailHandler和LogHandler,並執行它們的操做。
這裏,咱們使用了Publish 方法,而不是Send 函數。發佈將調用訂閱了NewUser 類的全部處理程序。這只是一個示例,咱們能夠根據命令進行思考,而後按照咱們在命令模式中討論的方式相應地執行一些操做。
它能夠用來隱藏實現的細節,用來使控制器代碼更加乾淨和可維護,能夠重用多個處理程序,而且每一個處理程序都有本身的責任,所以易於管理和維護。
在個人下一篇文章中,我將嘗試解釋CQRS架構模式及其優勢以及如何使用MediatR來實現CQRS。
原文地址:https://www.c-sharpcorner.com/article/command-mediator-pattern-in-asp-net-core-using-mediatr2/