中介者模式及在NetCore中的使用MediatR來實現

在現實生活中,經常會出現好多對象之間存在複雜的交互關係,這種交互關係經常是「網狀結構」,它要求每一個對象都必須知道它須要交互的對象。例如,每一個人必須記住他(她)全部朋友的電話;並且,朋友中若是有人的電話修改了,他(她)必須告訴其餘全部的朋友修改,這叫做「牽一髮而動全身」,很是複雜。

若是把這種「網狀結構」改成「星形結構」的話,將大大下降它們之間的「耦合性」,這時只要找一個「中介者」就能夠了。如前面所說的「每一個人必須記住全部朋友電話」的問題,只要在網上創建一個每一個朋友均可以訪問的「通訊錄」就解決了。這樣的例子還有不少,例如,你剛剛參力口工做想租房,能夠找「房屋中介」;或者,本身剛剛到一個陌生城市找工做,能夠找「人才交流中心」幫忙。

在軟件的開發過程當中,這樣的例子也不少,例如,在 MVC 框架中,控制器(C)就是模型(M)和視圖(V)的中介者;還有你們經常使用的 QQ 聊天程序的「中介者」是 QQ 服務器。全部這些,均可以採用「中介者模式」來實現,它將大大下降對象之間的耦合性,提升系統的靈活性。服務器

中介者模式的適用場景

通常在如下狀況下能夠考慮使用中介者模式:框架

  1. 一組定義良好的對象,如今要進行復雜的相互通訊。
  2. 想經過一箇中間類來封裝多個類中的行爲,而又不想生成太多的子類。

模式的定義與特色

中介者(Mediator)模式的定義:定義一箇中介對象來封裝一系列對象之間的交互,使原有對象之間的耦合鬆散,且能夠獨立地改變它們之間的交互。中介者模式又叫調停模式,它是迪米特法則的典型應用。

中介者模式是一種對象行爲型模式,其主要優勢以下。spa

  1. 下降了對象之間的耦合性,使得對象易於獨立地被複用。
  2. 將對象間的一對多關聯轉變爲一對一的關聯,提升系統的靈活性,使得系統易於維護和擴展。


其主要缺點是:當同事類太多時,中介者的職責將很大,它會變得複雜而龐大,以致於系統難以維護。code

廣義中介者

在實際開發中,常常會簡化中介者模式,來是開發變得簡單,好比有以下的簡化。對象

  1.  一般會去掉同事對象的父類,這樣可讓任意的對象,只須要有交互,就能夠成爲同事
  2.  一般不定義Mediator接口,把具體的中介者對象實現成爲單例
  3.  同事對象再也不持有中介者,而是在須要的時候直接獲取中介者對象並調用;中介者也再也不持有同事對象,而是在具體處理方法裏面去建立,或獲取,或從數據傳入須要的同事對象。

通過這樣的簡化、變形的狀況稱爲廣義中介者。blog

簡而概之(僞代碼演示)

中介者模式就是經過一箇中介者,來讓多個交錯縱橫的引用的類相互解耦,經過訪問中介者類的方法就能夠訪問其餘類的方法,每一個類之間是相互平等的。好比下面的代碼,咱們有一個學生類,一個教師類,咱們在控制器中有兩個Action來處理這兩個類的新增,那咱們的實現應該是以下的:繼承

public class Student{//屬性...}
public class Teacher{//屬性...}

服務類接口

public class StudentService
{
  public void Add(Student entity){//添加方法}
}
public class TeacherService
{
  public void Add(Teacher entity){//添加方法}
}

控制器的實現,能夠看到有多個服務類被實例化。開發

public class AddController : Controller
{
  StudentService studentService = new StudentService();
  TeacherService teacherService = new TeacherService();
  public IActionResult Student(Student entity)
  {
    studentService.Add(entity);
    return Content("添加成功");
  }
  public IActionResult Teacher(Teacher entity)
  {
    teacherService.Add(entity);
    return Content("添加成功");
  }
}

若是咱們用了中介者模式,那就能夠免去這些服務類的實例化,直接使用中介者類執行對應的添加方法就好了,下面就進行簡單的實現。get

中介者模式的簡單實現

下面只是經過簡單的例子來體現中介者模式的思想,不用過於糾結是否合理,咱們能夠在實際項目中按本身的需求來實現,就想上面描述的廣義的中介者模式。

學生類和教師類以及對應的服務類

public class Base{}
public class Student : Base{//屬性...}
public class Teacher : Base{//屬性...}
public class StudentService
{
    public string Add(Student entity){return "已添加學生";}
}
public class TeacherService
{
    public string Add(Teacher entity){return "已添加教師";}
}

中介者類

public interface IMediator{string Add(Base entity);}
public class Mediator : IMediator
{
    private StudentService studentService = new StudentService();
    private TeacherService teacherService = new TeacherService();
    public string Add(Base entity)
    {
        if(entity is Student)
            return studentService.Add((Student)entity);
        else if (entity is Teacher)
            return teacherService.Add((Teacher)entity);
        return "添加失敗";
    }
}

控制器中使用中介者類

public class AddController : Controller
{
    private IMediator iMediator = new Mediator();
    public IActionResult Student(Student entity)
    {
        return Content(iMediator.Add(entity));
    }
    public IActionResult Teacher(Teacher entity)
    {
        return Content(iMediator.Add(entity));
    }
}

訪問學生新增接口就會出現以下結果:

 在NetCore中使用MediatR實現中介者模式

經過 .NET CORE 自帶的 IoC 注入

引用 MediatR nuget:install-package MediatR

引用IOC擴展 nuget:installpackage MediatR.Extensions.Microsoft.DependencyInjection //擴展包

在Startup類中的ConfigureServices方法中註冊MediatR服務,下面這句話能夠掃描繼承IRequestHandler接口的實現對象並添加到IOC的容器中

services.AddMediatR(typeof(Startup).GetTypeInfo().Assembly);

爲咱們的學生類和教師類繼承IRequest接口,表示該對象是處理器的一個對象。

public class Student : IRequest<string>{//屬性...}
public class Teacher : IRequest<string>{//屬性...}

爲咱們的服務類添加IRequestHandler接口建立處理器對象。

public class StudentService : IRequestHandler<Student,string>
{
    public Task<string> Handle(Student entity, CancellationToken cancellationToken)
    {
        return Task.FromResult("已添加學生");
    }
}
public class TeacherService : IRequestHandler<Teacher, string>
{
    public Task<string> Handle(Teacher entity, CancellationToken cancellationToken)
    {
        return Task.FromResult("已添加教師");
    }
}

在控制器中使用,經過調用中介者的Send方法,自動匹配對應使用該處理器對象的處理器方法。

public class AddController : Controller
{
    private readonly IMediator _mediator;

    public AddController(IMediator mediator)
    {
        _mediator = mediator;
    }
    public IActionResult Student(Student entity)
    {
        return Content(_mediator.Send(entity).Result);
    }
    public IActionResult Teacher(Teacher entity)
    {
        return Content(_mediator.Send(entity).Result);
    }
}

這樣咱們的改造就完成了。繼承IRequest接口有一個泛型表示處理器返回參數類型,與IRequestHandler接口的第二個參數和IRequestHandler接口定義的方法Handle方法的返回值對應,能夠不定義表示返回void。IRequestHandler接口的第一個參數必須爲繼承IRequest接口的類。

相關文章
相關標籤/搜索