钱行慕

导航

【译】.NET Core中的中介者模式-第二部分-Roll Your Own

原文链接:传送门

这是关于在.NET Core中使用中介者模式的系列的第二部分。如果你从此处开始那么很可能会错过一些重要的事情,因而在你继续阅读之前,请确保回过头来阅读第一部分。

IEnumerable 模式

IEnumerable是过去5年我一直在我独自工作的项目中使用的一些东西。它最终证明是一件很棒的特性,当我发现如果你绑定多个类型到一个相同的接口,几个IOC容器会自动将一个 IEnumerable<T> 注入一个类(这听起来会让我迷惑,但当我们开始看代码的时候就会发现其很有道理)。

这块我使用的代码并不是明确的“中介者”模式。但是当我考虑“中介者”模式的核心定义特性的时候,我时刻记得:

其通过使得对象之间不进行显示的相互引用而减少耦合。

这非常接近于这样做。

让我们来看看一个示例。对于这个我将使用标准的.NET Core web API工程。没有什么神奇的。在这段代码中,我有一个接口,并具有这个接口的两个实现。

public interface INotifier
{
    void Notify();
}

public class Notifier1 : INotifier
{
    public void Notify()
    {
        Debug.WriteLine("Debugging from Notifier 1");
    }
}

public class Notifier2 : INotifier
{
    public void Notify()
    {
        Debug.WriteLine("Debugging from Notifier 2");
    }
}

 在我的startup.cs类中,我将这两个类绑定到INotifier 接口。

public void ConfigureServices(IServiceCollection services)
{
    services.AddTransient<INotifier, Notifier1>();
    services.AddTransient<INotifier, Notifier2>();
    services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
}

 接着我用一个超级简单的控制器来演示我所做的。

public class HomeController : ControllerBase
{
    private readonly IEnumerable<INotifier> _notifiers;

    public HomeController(IEnumerable<INotifier> notifiers)
    {
        _notifiers = notifiers;
    }

    [HttpGet("")]
    public ActionResult<string> NotifyAll()
    {
        _notifiers.ToList().ForEach(x => x.Notify());
        return "Completed";
    }
}

我访问这个终结点,在我的调试窗口,我将看到什么?

超级简单,对吧?现在当我添加,移除,或者更改notifiers,或者但它们运行时候需要增加额外的逻辑。列表本身每次很容易被注入到控制器(并且也很容易被注入到任何地方)。在这种方式下,当额外的类被添加或者移除时,调用者实际上不需要做什么改变,并且它不需要扩展它的行为,将保持完全一致。

让其更具有“中介者”的风格

看到这个的一些人或许会感觉它仍缺乏一些实现细节。但是如果我们真的想以中介者服务类的形式来实现所有这些,这是很容易封装的。举个例子,让我们创建一个像这样的服务:

public interface INotifierMediatorService
{
    void Notify();
}

public class NotifierMediatorService : INotifierMediatorService
{
    private readonly IEnumerable<INotifier> _notifiers;

    public NotifierMediatorService(IEnumerable<INotifier> notifiers)
    {
        _notifiers = notifiers;
    }

    public void Notify()
    {
        _notifiers.ToList().ForEach(x => x.Notify());
    }
}

在我们的startup.cs类的ConfigureServices,我们需要用下面的一行来注册这个新的服务:

services.AddTransient<INotifierMediatorService, NotifierMediatorService>();

 最终,我们需要将所有这些组装起来使用,让我们更改我们的控制器使其看起来像是这样:

public class HomeController : ControllerBase
{
    private readonly INotifierMediatorService _notifierMediatorService;

    public HomeController(INotifierMediatorService notifierMediatorService)
    {
        _notifierMediatorService = notifierMediatorService;
    }

    [HttpGet("")]
    public ActionResult<string> NotifyAll()
    {
        _notifierMediatorService.Notify();
        return "Completed";
    }
}

这相当的时髦并且更服务中介者模式,并且仍然提供给了我们中介者模式的优雅:当我们添加或者移除handlers时不需要不断的更改。

额外的handlers

当不严格受限于中介者模式时,你将也会发现中介者模式的类库提供了一些方式来有条件的运行一个handler。这或许会基于特定的情形或者一个特定的类。在结束时候,我给出的一个极其普遍的做法是某种被放置在接口中的“CanRun”方法。它可以接收输入或者仅仅在后台检查一些数据。它看起来可能会像是这样:

ublic interface INotifier
{
    void Notify();
    bool CanRun();
}

public class Notifier1 : INotifier
{
    public void Notify()
    {
        Debug.WriteLine("Debugging from Notifier 1");
    }

    public bool CanRun()
    {
        //Check something. And return True if it can run. 
        return true;
    }
}

当我们需要从一个list中执行它的时候,我们可以使用Linq来过滤它们:

_notifiers.Where(x => x.CanRun()).ToList().ForEach(x => x.Notify());

我用了很多不同的方法做了这件事,取得了巨大的成功。

 接下来?

在此系列的下一篇文章,我们将研究下“MediatR”库。一个在.NET中非常流行的实现了中介者模式的类库。

 

posted on 2020-07-19 18:26  钱行慕  阅读(206)  评论(0编辑  收藏  举报