【发布时间】:2018-03-31 14:52:55
【问题描述】:
我正在开发一个内部库,供我所在公司的其他开发人员使用。我正在应用 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);。我公司的开发人员习惯于看到静态方法,我认为这种方法对他们来说可能是可取的。
我的问题是:
- 这是解决我问题的最佳方法吗?
- 我是否违反了任何最佳做法?
- 是否有描述 CommonCatalog 类的设计模式?它是“门面”还是“代理”?
TLDR:我公司的开发人员喜欢使用静态方法,但静态方法与 DI 和 SOLID 实践不兼容。有没有什么办法让人们误以为他们使用的是静态方法,但在幕后调用了 DI 代码?
【问题讨论】:
-
我认为您已经回答了第二个问题;这种静态方法调用的方法违反了最佳实践。 DI in .NET 描述了您在第 5 章(反模式)和第 6 章(代码异味)中描述的大部分内容。但是,作为架构师,您需要考虑当前对开发人员和遗留软件的理解,所以除了您之外没有人可以回答第一个问题;这个问题非常主观,甚至可能使您的问题结束。您的
CommonCatalog使用外观 (+)、服务定位器 (-) 和环境上下文 (-)。
标签: c# dependency-injection webforms ioc-container legacy-code