现在我们使用DI / IOC,当我们需要将额外的参数传递给构造函数时,我们使用工厂类,例如。
public class EmailSender
{
internal EmailSender(string toEmail, string subject,String body, ILogger emailLogger)
{.....}
}
public class EmailSenderFactory
{
ILogger emailLogger;
public EmailSenderFactory(ILogger emailLogger)
{
this.emailLogger = emailLogger;
}
public EmailSender Create(string toEmail, string subject, string body)
{
return new EmailSender(toEmail, subject, body, emailLogger);
}
}
现在问题在于我们最终创建了一个完整的工厂类,人们并不总是知道使用它们(有时他们自己新建)。编写这类课程的最大负面因素是:
public class EmailSender
{
EmailLogger logger = IoC.Resolve<ILogger>();
internal EmailSender(string toEmail, string subject,String body)
{.....}
}
Pro:我们现在可以安全地使用构造函数而无需工厂类 Con:我们必须引用服务定位器(我不担心可测试性,它很容易使用模拟容器作为容器的支持服务)。
为什么我们不应该这样做,有什么大的原因吗?
编辑:经过一番思考后,我通过拥有一个私有构造函数来解决这个问题,并且通过嵌套Factory类,我可以将实现和工厂保持在一起,并防止人们不正确地创建类,所以这个问题变得有些没有实际意义。所有关于SL的点都很脏,当然是正确的,所以下面的解决方案让我感到高兴:
public class EmailSender
{
public class Factory
{
ILogger emailLogger;
public Factory(ILogger emailLogger)
{
this.emailLogger = emailLogger;
}
public EmailSender Create(string toEmail, string subject, string body)
{
return new EmailSender(toEmail, subject, body, emailLogger);
}
}
private EmailSender(string toEmail, string subject,String body, ILogger emailLogger)
{
}
}
答案 0 :(得分:14)
另一个更重要的方面, 是你的组件绑定 你的服务定位器。
您现在无法实例化它们 就像那样 - 你需要一个 完全设置服务定位器 每次你需要使用一个地方 成分
答案 1 :(得分:2)
我能想到的最大原因(不仅仅是查看服务定位器的问题)是因为我不是我班级用户expect。
元讨论:
一些DI框架(例如Guice)将build the factory for you。
有些人advocate将“新手”与“注射”分开。
答案 2 :(得分:1)
我不太确定Krzysztof给出的这个强烈的“这是坏的”答案。我认为在那里存在一些权衡和偏好而没有将它们完全归类为坏或好。
我认为使用服务定位器确实将您的依赖项隐藏在类中,而不是通过构造函数公开它们。在我看来这是不方便的,因为在没有配置服务定位器的情况下,你不会知道你的类缺少了什么。
但DI的东西并没有摆脱那种代码的黑暗。当你使用DI时,理解那些依赖关系是如何在你的构造函数中“出现”(DI魔术)真的不明显。通过使用SL,您至少可以看到这些依赖项的来源。
但是,当测试一个在她的构造函数上暴露这些依赖项的类时,你(几乎)不能错过它。使用服务定位器的情况并非如此。
我不是说Krzysztof错了,因为我最同意他。但我非常确定使用服务定位器不一定是一个糟糕的“设计”,当然不是简单的坏。
菲尔