我正在开发一个内部库,供我正在为之工作的公司中的其他开发人员使用。我正在应用SOLID模式并遵循Dependency Inject (DI) “friendly” library中描述的最佳实践。
我的最终用户将是不同应用程序的开发人员。其中一些是没有DI的复杂遗留应用程序,另一些是具有DI和TDD的新应用程序。
现在,我试图弄清楚如何从没有实现DI的遗留ASP.NET Webforms应用程序中调用这个DI友好库,显然,我无法修改250多个aspx页面以支持构造函数注入因为它超出了我的项目范围。 (Yes, I have read Introducing an IoC Container to Legacy Code )
我的一个想法是为Common Service Locator创建一个静态全局包装器,以自动解决整个应用程序中的依赖关系:
public static class GlobalResolver
{
public static T Resolve<T>()
{
return ServiceLocator.Current.GetInstance<T>();
}
}
这种方法的好处是我可以在我的合成根中使用任何IoC库(我目前使用Unity)。我会像这样使用这个GlobalResolver:
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>
行感到困惑,所以我试图看看是否有替代方案。
我想到的一件事是这样的:
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);
。我公司的开发人员习惯于看静态方法,我认为这种方法对他们来说可能是理想的。
我的问题是:
TLDR:我公司的开发人员喜欢使用静态方法,但静态方法与DI和SOLID实践不兼容。有没有办法诱骗人们认为他们正在使用静态方法,但在幕后调用DI代码?
答案 0 :(得分:1)
如果你想避开Service Locator anti-pattern(你应该这样做,因为 - 它是反模式),那么带GlobalResolver
的第一个选项是不可能的,因为it's definitely a Service Locator
服务目录更接近我在Facades的扩展文章中推荐的DI-friendly libraries,尽管我通常不喜欢没有聚合的对象目录。当我不知道如何命名对象时,它总是让我感到不舒服,像CommonCatalog
这样的名字似乎太缺乏意义。
相反,我更倾向于使用文章中描述的Fluent Builder模式制作基于实例的Facade,因为当您在线下发现需要添加各种选项时,它会更灵活。切换到立面。
但是,如果绝对必须,可以为每个Facade添加静态方法。像这样:
public static class Mailer
{
public static IMailer Default
{
get { return new MailerBuilder().Create(); }
}
}
如果实例可以想象具有单身生命周期,则可以使用Singleton design pattern,如下一个示例所示。
你可以用同样的方式实现一个默认的MessageFactory,但是这里改为使用Singleton设计模式:
public static class MailMessageFactory
{
public static IMailMessageFactory Default { get } =
new MailMessageFactoryBuilder().Create();
}
请注意,这并没有使用服务定位器来实现。
要明确的是,背后这样的外观可以很容易地根据SOLID原则实现,但是调用代码仍然很难做到这一点。