DI容器,工厂或新的短暂物体?

时间:2010-01-13 22:27:23

标签: dependency-injection new-operator factory

当处理需要在运行时只知道数据的对象时,例如用户名和密码,应该在何处进行对象实例化:使用new,在工厂或DI容器中?

例如,一旦有了数据,我就可以new一个对象:

UserCredentials creds =
    new UserCredentials(dialog.getUsername(), dialog.getPassword());

或者,我可以使用工厂:

UserCredentials creds =
    CredentialsFactory.create(dialog.getUsername(), dialog.getPassword());

或者,我可以在DI容器中使用提供程序(在这种情况下,它基本上是一个参数驱动的工厂)。 [省略示例代码。]

将DI容器用于如此简单的事情似乎都是错误的,但如果不充分利用它也似乎是错误的。

4 个答案:

答案 0 :(得分:8)

与往常一样,这取决于,但作为一般规则,像第二种选择这样的静态工厂很少是一个好主意。

new使用UserCredential对象似乎是一个公平的选择,因为UserCredentials类看起来像一个自包含的具体类,可以使用用户名和密码完全实例化其所有不变量。

在其他情况下,您要创建的类型本身可能代表抽象。如果是这种情况,则无法使用new关键字,但必须使用抽象工厂

使用抽象工厂通常非常有价值,因为它允许您从运行时值和其他依赖项的组合中组合实例。有关详细信息,请参阅here

使用抽象工厂也有助于单元测试,因为您可以简单地测试返回值或结束状态或您关心的任何内容与抽象工厂的输出相关 - 您可以为此轻松提供测试双重,因为它是......抽象的。

答案 1 :(得分:3)

Google测试博客有a post which tries to answer this question。基本的想法是,你可以将你的每个类分类为“新的”或“可注射的”,并且可以“新建”新的。

我区分了两个主要类别的“新手”:

  • intstringDateTime等等。
  • 类似CustomerOrderEmployee等实体。我认为您的UserCredentials课程属于此标题。

重要的是要意识到 newables可以拥有(可测试的)行为。如果你错误地认为newables不应该有任何行为或单元测试,你最终会得到anemic domain model反模式。

使用“newables”行为的副作用是,在注射剂的单元测试中不能抽象出这种行为。还行吧;在您的域模型和应用程序的其余部分之间建立一些强大的耦合是正常的。

此外,允许新人知道注射剂,但他们只是暂时与他们合作。例如,UserCredentials不应将IUserDatabase作为构造函数参数。相反,可能有UserCredentials.Verify(IUserDatabase)方法。

编辑:我目前对我上面写的内容不太了解。实体也可以通过(可注入的)工厂构建,而不是直接调用它们的构造函数。然后,工厂实现可以在实体中注入内容。

答案 2 :(得分:0)

对我来说,我使用DI来创建对象之间更松散的耦合。如果您的对象依赖项受到使用new创建对象的影响很大,那么我不明白为什么您不能将DI或中继对象创建用于工厂。这为您提供了更多控制,并使您的课程保持松散耦合。

这实际上取决于你何时何地需要这个对象,以及结果是否会有不必要的依赖。

答案 3 :(得分:0)

如果您已经为您的应用程序设置了DI容器,那么请使用此方法。如果没有,请使用工厂方法。