引用的大多数使用依赖注入的例子,我们也可以使用工厂模式来解决。看起来当涉及到使用/设计时,依赖注入和工厂之间的区别是模糊或稀薄的。

曾经有人告诉我,你如何使用它才会有所不同!

我曾经使用StructureMap一个DI容器来解决一个问题,后来我重新设计了它来使用一个简单的工厂,并删除了对StructureMap的引用。

谁能告诉我它们之间的区别在哪里使用什么,这里的最佳实践是什么?


当前回答

当使用工厂时,您的代码实际上仍然负责创建对象。通过DI,你可以将职责外包给另一个类或框架,这与你的代码是分开的。

其他回答

我认为它们是正交的,可以一起使用。让我给你看一个我最近在工作中遇到的例子:

我们使用Java中的Spring框架进行DI。一个单例类(Parent)必须实例化另一个类(Child)的新对象,这些对象有复杂的协作者:

@Component
class Parent {
    // ...
    @Autowired
    Parent(Dep1 dep1, Dep2 dep2, ..., DepN depN) {
        this.dep1 = dep1;
        this.dep2 = dep2;
    }

    void method(int p) {
        Child c = new Child(dep1, dep2, ..., depN, p);
        // ...
    }
}

在这个例子中,Parent必须接收DepX实例,并将它们传递给Child构造函数。问题在于:

Parent对Child的了解比它应该了解的要多 母公司的合作者太多了 向Child添加依赖项需要更改Parent

这时我意识到工厂非常适合这里:

它隐藏了Child类的所有真实参数,就像Parent所看到的那样 它封装了创建子节点的知识,这些知识可以集中在DI配置中。

这是简化的Parent类和ChildFactory类:

@Component
class Parent {
    // ...
    @Autowired
    Parent(ChildFactory childFactory) {
        this.childFactory = childFactory;
    }

    void method(int p) {
        Child c = childFactory.newChild(p);
        // ...
    }
}

@Component
class ChildFactory {
    // ...
    @Autowired
    Parent(Dep1 dep1, Dep2 dep2, ..., DepN depN) {
        this.dep1 = dep1;
        this.dep2 = dep2;
        // ...
        this.depN = depN;
    }

    Child newChild(int p) {
        return new Child(dep1, dep2, ..., depN, p);
    }
}

当您确切地知道此时需要什么类型的对象时,就可以使用依赖项注入。而在工厂模式的情况下,你只是把创建对象的过程委托给工厂,因为你不清楚你需要什么类型的对象。

当使用工厂时,您的代码实际上仍然负责创建对象。通过DI,你可以将职责外包给另一个类或框架,这与你的代码是分开的。

我相信DI是一种配置或即时化bean的方法。DI可以通过很多方式来实现,比如构造函数,setter-getter等等。

工厂模式只是实例化bean的另一种方式。此模式将主要用于必须使用工厂设计模式创建对象时,因为在使用此模式时,您不配置bean的属性,只实例化对象。

检查这个链接:依赖注入

DI为您提供了一个组合根,这是连接对象图的一个集中位置。这往往使对象依赖关系非常显式,因为对象确切地要求它们所需要的东西,并且只有一个地方可以得到它。

组合根是一种清晰而直接的关注点分离。被注入的对象应该不依赖于DI机制,无论是第三方容器还是DIY DI。DI应该是不可见的。

工厂往往更加分散。不同的对象使用不同的工厂,工厂表示对象与其实际依赖关系之间的额外间接层。这个附加层将自己的依赖项添加到对象图中。工厂不是看不见的。工厂是一个中间商。

因此,更新工厂的问题更大:因为工厂是业务逻辑的依赖项,修改它们可能会产生连锁反应。组合根不是业务逻辑的依赖项,因此可以单独修改它。

GoF提到了更新抽象工厂的困难。他们的部分解释被引用在这里的回答中。将DI与工厂进行对比也与ServiceLocator是否是反模式这个问题有很多相似之处。

最终,选择哪个答案可能是固执己见的;但我认为这可以归结为一个工厂是一个中间人。问题在于,除了提供产品之外,这个中间商是否还能通过增加额外价值来发挥自己的作用。因为如果你能在没有中间商的情况下得到同样的产品,那为什么不把中间商去掉呢?

一个图表有助于说明其中的区别。