引用的大多数使用依赖注入的例子,我们也可以使用工厂模式来解决。看起来当涉及到使用/设计时,依赖注入和工厂之间的区别是模糊或稀薄的。
曾经有人告诉我,你如何使用它才会有所不同!
我曾经使用StructureMap一个DI容器来解决一个问题,后来我重新设计了它来使用一个简单的工厂,并删除了对StructureMap的引用。
谁能告诉我它们之间的区别在哪里使用什么,这里的最佳实践是什么?
引用的大多数使用依赖注入的例子,我们也可以使用工厂模式来解决。看起来当涉及到使用/设计时,依赖注入和工厂之间的区别是模糊或稀薄的。
曾经有人告诉我,你如何使用它才会有所不同!
我曾经使用StructureMap一个DI容器来解决一个问题,后来我重新设计了它来使用一个简单的工厂,并删除了对StructureMap的引用。
谁能告诉我它们之间的区别在哪里使用什么,这里的最佳实践是什么?
当前回答
这里的大多数答案都解释了两者的概念差异和实现细节。但是我无法解释在应用上的差异,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
当您确切地知道此时需要什么类型的对象时,就可以使用依赖项注入。而在工厂模式的情况下,你只是把创建对象的过程委托给工厂,因为你不清楚你需要什么类型的对象。
当使用工厂时,您的代码实际上仍然负责创建对象。通过DI,你可以将职责外包给另一个类或框架,这与你的代码是分开的。
我使用这两种方法来创建反转控制策略,为在我之后需要维护它的开发人员提供了更强的可读性。
我使用工厂来创建不同的层对象(业务,数据访问)。
ICarBusiness carBusiness = BusinessFactory.CreateCarBusiness();
另一个开发人员会看到这一点,当创建业务层对象时,他会在BusinessFactory中查看,智能感知会为开发人员提供所有可能创建的业务层。不需要玩游戏,找到我想要创建的界面。
这个结构已经是控制反转了。我不再负责创建特定的对象。但是您仍然需要确保依赖注入能够轻松地更改内容。 创建自己的自定义依赖注入是荒谬的,所以我使用Unity。在CreateCarBusiness()中,我要求Unity解决哪个类属于这个和它的生命周期。
所以我的代码工厂依赖注入结构是:
public static class BusinessFactory
{
public static ICarBusiness CreateCarBusiness()
{
return Container.Resolve<ICarBusiness>();
}
}
现在我两者兼得。我的代码对于其他开发人员来说也更易于阅读,因为我使用的对象的范围,而不是构造函数依赖注入,它只是说在创建类时每个对象都是可用的。
当我创建单元测试时,我使用它将我的数据库数据访问更改为自定义编码的数据访问层。我不希望我的单元测试与数据库、网络服务器、电子邮件服务器等通信。他们需要测试我的业务层,因为这是智能所在。
我的想法:
依赖注入:将协作者作为参数传递给构造函数。 依赖注入框架:一个通用的、可配置的工厂,用于创建对象,并将其作为参数传递给构造函数。