创建对象“目录”。用于不可知论的图书馆 [英] Creating object "Catalog" for DI agnostic library

查看:82
本文介绍了创建对象“目录”。用于不可知论的图书馆的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在开发一个内部库,供我工作的公司中的其他开发人员使用。我正在应用SOLID模式并遵循依赖注入(DI)中所述的最佳做法友好库

I am developing an internal library that is to be used by other developers in the company that I'm working for. I am applying SOLID patterns and following the best practices as described in Dependency Inject (DI) "friendly" library.

我的最终用户将是不同应用程序的开发人员。其中一些是没有DI的复杂的旧版应用程序,而另一些是具有DI和TDD的较新的应用程序。

My end users would be developers of different applications. Some of them are complex legacy applications with no DI, and others are newer apps that have DI and TDD.

现在,我试图弄清楚如何称呼这个DI一个旧的ASP.NET Webforms应用程序中的一个友好库,其中没有实现DI,很显然,我不能修改250+个aspx页面来支持构造函数注入,因为它超出了我的项目范围。 (是的,我已阅读了将IoC容器引入旧版代码

Now, I am trying to figure out how to call this DI friendly library from a legacy ASP.NET Webforms application that has no DI implemented in it, and obviously, I can't revise 250+ aspx pages to support constructor injection because it is out of scope of my project. (Yes, I have read Introducing an IoC Container to Legacy Code )

一个想法是我为Common Service Locator创建了一个静态全局包装器,以自动解决整个应用程序中的依赖关系:

One idea that I had was creating a static global wrapper for Common Service Locator to automatically resolve dependencies throughout the app:

public static class GlobalResolver
{
    public static T Resolve<T>()
    {
        return ServiceLocator.Current.GetInstance<T>();
    }
}

这种方法的好处是我可以使用我的合成根目录中的任何IoC库(我目前使用Unity)。我会这样使用GlobalResolver:

The nice thing about this approach is that I can use any IoC library in my composition root (I currently use Unity). I would use this GlobalResolver like this:

protected void OnClick(object sender, EventArgs e)
{
    IMailMessage message = MessageFactory.Create("Jack.Daniels@jjj.com", "John.Doe@jjj.com", "subject", "Body", true, MailPriority.High);
    GlobalResolver.Resolve<IMailer>().SendMail(message);
}

我喜欢这种方法,我认为它很干净,但是我公司的新手开发人员可能对此 GlobalResolver.Resolve< IMailer> 行感到困惑,所以我试图看看是否还有替代方法。

I like this approach and I think it's clean, but novice developers in my company might get confused with this GlobalResolver.Resolve<IMailer> line, so I'm trying to see if there is alternative to this out there.

我想到的一件事是这样的:

One thing that comes to my mind is something like this:

public static class CommonCatalog
{
    public static IMailer Mailer => ServiceLocator.Current.GetInstance<IMailer>();
    public static IMailMessageFactory MessageFactory => ServiceLocator.Current.GetInstance<IMailMessageFactory>();
    public static IFtpSecureClientFactory FTPClientFactory => ServiceLocator.Current.GetInstance<IFtpSecureClientFactory>();

    // And so on...
}

并像这样简单地使用它: CommonCatalog.Mailer.SendMail(message); 。我公司的开发人员习惯于看到静态方法,我认为这种方法可能是他们所需要的。

And simply use it like this: CommonCatalog.Mailer.SendMail(message);. Developers at my company are used to seeing static methods, and I think this approach might be desirable for them.

我的问题是:


  1. 这是解决我问题的最佳方法吗?

  2. 我违反了任何最佳做法吗?

  3. 是否有一种设计模式可以描述CommonCatalog类?是门面还是代理?

TLDR:我公司的开发人员喜欢使用静态方法,但静态方法是与DI和SOLID惯例不兼容。有什么办法欺骗人们以为他们在使用静态方法,但是在后台调用了DI代码?

TLDR: Developers at my company like to use Static methods, but static methods are incompatible with DI and SOLID practices. Is there any way to trick people into thinking that they are using static methods, but behind the scenes call DI code?

推荐答案

如果您要避免使用服务定位器反模式(您应该,因为-这是反模式),所以没有 GlobalResolver 的第一个选项是不可能的,因为这绝对是服务定位器

If you want to avoid the Service Locator anti-pattern (which you should, because - it's an anti-pattern), then the first option with a GlobalResolver is out of the question, because it's definitely a Service Locator.

服务目录更接近外观我在我的 DI友好的库,尽管我通常更喜欢没有聚合的对象目录。当我不知道如何命名对象时,总是让我感到不舒服,而像 CommonCatalog 这样的名称似乎太没有意义了。

The catalog of services is closer to the Facades I recommend in my expanded article on DI-friendly libraries, although I usually prefer not having an aggregated catalog of objects. It always makes me uncomfortable when I don't know how to name objects, and a name like CommonCatalog seems too devoid of meaning.

相反,我更喜欢使用本文所述的Fluent Builder模式制作基于实例的Facades,因为当您发现需要添加各种选项时,它往往更加灵活。切换到立面。

Rather, I'd prefer making instance-based Facades with the Fluent Builder pattern as described in the article, since it tends to be more flexible when you, down the line, discover that you need to add various options and switches to the facade.

但是,如果绝对必须,则可以为每个立面添加静态方法。这样的事情:

If you absolutely must, though, you can add a static method for each of the Facades. Something like this:

public static class Mailer
{
    public static IMailer Default
    {
        get { return new MailerBuilder().Create(); }
    }
}

如果该实例具有Singleton生存期,则可以,请使用 Singleton设计模式,如下例所示。

If the instance conceivably has Singleton lifetime, you can, instead, use the Singleton design pattern, as the next example demonstrates.

您可以以相同的方式实现默认的MessageFactory,但是这里使用Singleton设计模式:

You could implement a default MessageFactory the same way, but here instead using the Singleton design pattern:

public static class MailMessageFactory
{
    public static IMailMessageFactory Default { get } =
        new MailMessageFactoryBuilder().Create();
}

请注意,这也不使用Service Locator来实现。

Notice that this doesn't use a Service Locator for the implementation, either.

不过,要明确的是,根据SOLID原理,可以很容易地实现这样的Facades,但是调用代码仍然会包含一个很难。

To be clear, though, what's behind such Facades could easily be implemented according to the SOLID principles, but the calling code would still have a hard time doing that.

这篇关于创建对象“目录”。用于不可知论的图书馆的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆