C# “创建对象”;目录;不可知论图书馆
我正在开发一个内部库,供我所在公司的其他开发人员使用。我正在应用实体模式并遵循中所述的最佳实践 我的最终用户将是不同应用程序的开发人员。其中一些是没有DI的复杂遗留应用程序,另一些是具有DI和TDD的较新应用程序 现在,我正试图找出如何从一个没有实现DI的旧ASP.NET Webforms应用程序调用这个DI友好库,显然,我不能修改250+aspx页面来支持构造函数注入,因为它超出了我的项目范围。( ) 我的一个想法是为公共服务定位器创建一个静态全局包装器,以自动解决整个应用程序中的依赖关系:C# “创建对象”;目录;不可知论图书馆,c#,dependency-injection,webforms,ioc-container,legacy-code,C#,Dependency Injection,Webforms,Ioc Container,Legacy Code,我正在开发一个内部库,供我所在公司的其他开发人员使用。我正在应用实体模式并遵循中所述的最佳实践 我的最终用户将是不同应用程序的开发人员。其中一些是没有DI的复杂遗留应用程序,另一些是具有DI和TDD的较新应用程序 现在,我正试图找出如何从一个没有实现DI的旧ASP.NET Webforms应用程序调用这个DI友好库,显然,我不能修改250+aspx页面来支持构造函数注入,因为它超出了我的项目范围。( ) 我的一个想法是为公共服务定位器创建一个静态全局包装器,以自动解决整个应用程序中的依赖关系:
public static class GlobalResolver
{
public static T Resolve<T>()
{
return ServiceLocator.Current.GetInstance<T>();
}
}
公共静态类GlobalResolver
{
公共静态T解析()
{
返回ServiceLocator.Current.GetInstance();
}
}
这种方法的好处是,我可以使用我的合成根目录中的任何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);
}
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...
}
public static class Mailer
{
public static IMailer Default
{
get { return new MailerBuilder().Create(); }
}
}
protectedvoid OnClick(对象发送方,事件参数e)
{
IMailMessage=MessageFactory.Create(“杰克。Daniels@jjj.com约翰。Doe@jjj.com“,”主题“,”正文“,”真“,”优先权。高);
GlobalResolver.Resolve().SendMail(消息);
}
我喜欢这种方法,而且我认为它很干净,但是我公司的新手开发人员可能会对这条GlobalResolver.Resolve
行感到困惑,所以我正在尝试看看是否有其他替代方法
我想到的一件事是这样的:
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);
}
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...
}
public static class Mailer
{
public static IMailer Default
{
get { return new MailerBuilder().Create(); }
}
}
公共静态类CommonCatalog
{
公共静态iMail=>ServiceLocator.Current.GetInstance();
公共静态IMailMessageFactory MessageFactory=>ServiceLocator.Current.GetInstance();
公共静态IFtpSecureClientFactory FTPClientFactory=>ServiceLocator.Current.GetInstance();
//等等。。。
}
简单地使用它:CommonCatalog.Mailer.SendMail(message)代码>。我公司的开发人员习惯于看到静态方法,我认为这种方法对他们来说可能是可取的
我的问题是:
这是解决我问题的最好办法吗
我是否违反了任何最佳实践
是否有描述CommonCatalog类的设计模式?它是“门面”还是“代理”
TLDR:我公司的开发人员喜欢使用静态方法,但静态方法与DI和实体实践不兼容。有没有办法欺骗人们,让他们认为他们使用的是静态方法,但在幕后调用DI代码?如果你想避免这种情况(你应该这样做,因为这是一种反模式),那么使用GlobalResolver
的第一个选项是不可能的,因为
服务目录更接近于我在上的扩展文章中推荐的目录,尽管我通常不喜欢对象的聚合目录。当我不知道如何命名对象时,它总是让我感到不舒服,而像CommonCatalog
这样的名称似乎太没有意义了
相反,我更喜欢使用本文中描述的Fluent Builder模式制作基于实例的外观,因为当您发现需要向外观添加各种选项和开关时,它会更灵活
但是,如果必须这样做,可以为每个立面添加静态方法。大概是这样的:
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);
}
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...
}
public static class Mailer
{
public static IMailer Default
{
get { return new MailerBuilder().Create(); }
}
}
如果可以想象该实例具有单例生存期,则可以使用,如下一个示例所示
您可以用同样的方法实现默认MessageFactory,但这里使用的是Singleton设计模式:
public static class MailMessageFactory
{
public static IMailMessageFactory Default { get } =
new MailMessageFactoryBuilder().Create();
}
请注意,这也没有为实现使用服务定位器
不过,需要明确的是,这些外观背后的内容可以根据可靠的原则轻松实现,但调用代码仍然很难做到这一点。我认为您已经回答了第二个问题;这种静态方法调用的方法违反了自年以来的最佳实践。描述第5章(反模式)和第6章(代码气味)中描述的大部分内容。但是,作为架构师,您需要考虑到当前对开发人员和遗留软件的理解,因此除了您之外,没有人能够回答第一个问题;这个问题的主观性很强,甚至可能会让你的问题结束。您的CommonCatalog
使用Facade(+)、服务定位器(-)和环境上下文(-)。感谢您的输入。我在读你的书。我喜欢。干杯