使用servicelocation而不是构造函数注入来避免编写工厂类的负载是不好的

mci*_*321 7 c# java dependency-injection inversion-of-control service-locator

现在我们使用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);
    }
}
Run Code Online (Sandbox Code Playgroud)

现在问题是我们最终创建了一个完整的工厂类,人们并不总是知道使用它们(他们有时会自己创建它们).编写类的最大负面因素是:

public class EmailSender 
{
    EmailLogger logger = IoC.Resolve<ILogger>();
    internal EmailSender(string toEmail, string subject,String body)
    {.....} 
}
Run Code Online (Sandbox Code Playgroud)

Pro:我们现在可以安全地使用构造函数而无需工厂类Con:我们必须引用Service Locator(我不担心可测试性,它很容易使用模拟容器作为容器的支持服务).

是否有一些重要的原因,为什么我们不应该这样做?

编辑:经过一番思考,我通过拥有一个私有构造函数,并通过嵌套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)
    {
    } 
}
Run Code Online (Sandbox Code Playgroud)

Krz*_*mic 14

是的 - 这很糟糕.

  • 为什么在框架可以完成工作时编写所有代码?所有IoC.Resolve()调用都是多余的,您不必编写它们.
  • 另一个更重要的方面是您的组件与服务定位器绑定.

    您现在无法像这样实例化它们 - 每次需要使用组件时,您都需要一个完全设置的服务定位器.

  • 最后但是,机器人最少 - 你的SL代码遍布你的代码库,这不是一件好事,因为当你想要改变某些东西时,你必须在多个地方寻找.

  • 你不必写工厂类!IoC容器是一个可配置的uberfactory,如果你正确构建你的代码,它就是你所需要的 (4认同)