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

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

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

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


当前回答

有些问题用依赖注入很容易解决,而用一套工厂就不那么容易解决了。

一方面,控制反转和依赖注入(IOC/DI)与另一方面,服务定位器或工厂套件(factory)之间的一些区别是:

IOC/DI is a complete ecosystem of domain objects and services in and of itself. It sets everything up for you in the way you specify. Your domain objects and services are constructed by the container, and do not construct themselves: they therefore do not have any dependencies on the container or on any factories. IOC/DI permits an extremely high degree of configurability, with all the configuration in a single place (construction of the container) at the topmost layer of your application (the GUI, the Web front-end).

工厂抽象了域对象和服务的一些构造。但是领域对象和服务仍然负责弄清楚如何构造自己,以及如何获得它们所依赖的所有东西。所有这些“活动的”依赖项都会在应用程序的所有层中进行筛选。没有一个地方可以配置所有的东西。

其他回答

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

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

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

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

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

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

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

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

这里的大多数答案都解释了两者的概念差异和实现细节。但是我无法解释在应用上的差异,IMO是最重要的,OP问的是什么。所以让我重新讨论这个话题……

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

完全正确。在90%的情况下,你可以使用Factory或DI来获取对象引用,通常你最终会使用后者。在另外10%的情况下,使用Factory是唯一正确的方法。这些情况包括通过运行时参数的变量获取对象。是这样的:

IWebClient client = factoryWithCache.GetWebClient(url: "stackoverflow.com",
        useCookies: false, connectionTimeout: 120);

在这种情况下,从DI获取客户端是不可能的(或者至少需要一些丑陋的解决方案)。因此,作为决策的一般规则:如果可以在没有任何运行时计算参数的情况下获得依赖项,则首选DI,否则使用Factory。

依赖注入

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

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