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

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

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

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


当前回答

您可以在这个链接中查看两种(和其他)方法在实际示例中的比较。

基本上,当需求发生变化时,如果您使用工厂而不是DI,您最终会修改更多的代码。

这对于手动DI也是有效的(例如,当没有外部框架为你的对象提供依赖关系,但你在每个构造函数中传递它们时)。

其他回答

我使用这两种方法来创建反转控制策略,为在我之后需要维护它的开发人员提供了更强的可读性。

我使用工厂来创建不同的层对象(业务,数据访问)。

ICarBusiness carBusiness = BusinessFactory.CreateCarBusiness();

另一个开发人员会看到这一点,当创建业务层对象时,他会在BusinessFactory中查看,智能感知会为开发人员提供所有可能创建的业务层。不需要玩游戏,找到我想要创建的界面。

这个结构已经是控制反转了。我不再负责创建特定的对象。但是您仍然需要确保依赖注入能够轻松地更改内容。 创建自己的自定义依赖注入是荒谬的,所以我使用Unity。在CreateCarBusiness()中,我要求Unity解决哪个类属于这个和它的生命周期。

所以我的代码工厂依赖注入结构是:

public static class BusinessFactory
{
    public static ICarBusiness CreateCarBusiness()
    {
       return Container.Resolve<ICarBusiness>();
    }
}

现在我两者兼得。我的代码对于其他开发人员来说也更易于阅读,因为我使用的对象的范围,而不是构造函数依赖注入,它只是说在创建类时每个对象都是可用的。

当我创建单元测试时,我使用它将我的数据库数据访问更改为自定义编码的数据访问层。我不希望我的单元测试与数据库、网络服务器、电子邮件服务器等通信。他们需要测试我的业务层,因为这是智能所在。

我建议保持概念的简单明了。依赖注入更像是一种松散耦合软件组件的体系结构模式。工厂模式只是将创建其他类的对象的职责分离给另一个实体的一种方法。工厂模式可以被称为实现依赖注入的工具。依赖注入可以通过多种方式实现,比如使用构造函数进行依赖注入,使用映射xml文件等。

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

我们使用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);
    }
}

比诺,

我不认为你必须选择其中一个而不是另一个。

将依赖类或接口移动到类构造函数或setter的行为遵循DI模式。传递给构造函数或集合的对象可以用Factory实现。

什么时候使用?使用开发人员擅长的模式。他们觉得什么最舒服,什么最容易理解。

当我读到关于DI的文章时,我也有同样的问题。 最后,这就是我所理解的,但如果我错了,请纠正我。

“很久以前,有一些小国,它们有自己的管理机构,根据自己的成文规则进行控制和决策。后来形成了一个大政府,消除了所有这些小的管理机构,这些机构只有一套规则(宪法),并通过法院执行。”

小王国的管理机构是“工厂”

大政府是“依赖注入器”。