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

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

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

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


当前回答

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

其他回答

依赖注入的一个缺点是它不能用逻辑初始化对象。例如,当我需要创建一个随机名称和年龄的字符时,DI不是工厂模式的选择。使用工厂,我们可以很容易地从对象创建中封装随机算法,它支持一种称为“封装变化”的设计模式。

I believe, 3 important aspects govern objects and their usage: 1. Instantiation (of a class together with initialisation if any). 2. Injection (of the instance so created) where it's required. 3. Life cycle management (of the instance so created). Using Factory pattern, the first aspect (instantiation) is achieved but the remaining two is questionable. The class that uses other instances must hardcode the factories (instead of instances being created) which hinders loose coupling abilities. Moreover, life cycle management of instances becomes a challenge in a large application where a factory is used in multiple places (particularly, if the factory doesn't manage the life cycle of the instance it returns, it gets ugly). Using a DI (of IoC pattern) on the other hand, all the 3 are abstracted outside the code (to the DI container) and the managed bean needs nothing about this complexity. Loose Coupling, a very important architectural goal can be achieved quiet comfortably. Another important architectural goal, the separation of concerns can be achieved much better than factories.

尽管工厂可能适用于小型应用程序,但大型应用程序最好选择DI而不是工厂。

依赖注入

而不是实例化部件本身,汽车要求它的功能所需的部件。

class Car
{
    private Engine engine;
    private SteeringWheel wheel;
    private Tires tires;

    public Car(Engine engine, SteeringWheel wheel, Tires tires)
    {
        this.engine = engine;
        this.wheel = wheel;
        this.tires = tires;
    }
}

工厂

将各个部分组合在一起以形成一个完整的对象,并对调用者隐藏具体类型。

static class CarFactory
{
    public ICar BuildCar()
    {
        Engine engine = new Engine();
        SteeringWheel steeringWheel = new SteeringWheel();
        Tires tires = new Tires();
        ICar car = new RaceCar(engine, steeringWheel, tires);
        return car;
    }   
}

结果

正如你所看到的,工厂和DI是相辅相成的。

static void Main()
{
     ICar car = CarFactory.BuildCar();
     // use car
}

你还记得金发姑娘和三只熊吗?依赖注入有点像这样。这里有三种方法来做同样的事情。

void RaceCar() // example #1
{
    ICar car = CarFactory.BuildCar();
    car.Race();
}

void RaceCar(ICarFactory carFactory) // example #2
{
    ICar car = carFactory.BuildCar();
    car.Race();
}

void RaceCar(ICar car) // example #3
{
    car.Race();
}

例#1——这是最糟糕的,因为它完全隐藏了依赖关系。如果你把这个方法看作一个黑盒子,你就不会知道它需要一辆车。

例2——这样会好一点,因为我们经过了一家汽车厂,现在我们知道我们需要一辆车。但是这次我们传递的太多了,因为这个方法实际上只需要一个car。我们正在路过一个工厂,只是为了建造汽车,当汽车可以在外面建造的方法和通过。

示例#3—这是理想的,因为该方法要求的正是它所需要的。不要太多也不要太少。我不需要为了创建MockCars而编写MockCarFactory,我可以直接传入mock。它是直接的,界面不会说谎。

Misko Hevery的谷歌技术演讲非常棒,这是我得到我的例子的基础。http://www.youtube.com/watch?v=XcT4yYu_TTs

依赖注入(DI)和工厂模式相似的原因是它们是控制反转(IoC)的两种实现,IoC是一种软件架构。简单地说,它们是同一问题的两种解决方案。

因此,为了回答这个问题,工厂模式和依赖注入模式之间的主要区别在于如何获得对象引用。依赖项注入顾名思义就是将引用注入或提供给您的代码。使用工厂模式,您的代码必须请求引用,以便您的代码获取对象。这两种实现都删除或解耦了代码与所使用的对象引用的底层类或类型之间的链接。

值得注意的是,工厂模式(或者实际上是抽象工厂模式,即返回返回对象引用的新工厂的工厂)可以被编写为在运行时动态地选择或链接到被请求的对象类型或类。这使得它们与服务定位器模式非常相似(甚至比DI更相似),后者是IoC的另一个实现。

工厂设计模式相当古老(就软件而言),并且已经存在了一段时间。由于IoC体系结构模式最近的流行,它正在复苏。

我想当涉及到IoC设计模式时:注入器被注入,定位器被定位,工厂被重构。

简单来说,依赖注入和工厂方法分别意味着推和拉机制。

拉机制:类间接依赖于工厂方法,工厂方法又依赖于具体类。

推送机制:根组件可以在一个位置配置所有依赖组件,从而促进高维护和松耦合。

使用Factory方法时,创建新对象的责任仍然由类承担(尽管是间接的),而使用依赖注入时,责任是外包的(尽管是以泄露抽象为代价)。