引用的大多数使用依赖注入的例子,我们也可以使用工厂模式来解决。看起来当涉及到使用/设计时,依赖注入和工厂之间的区别是模糊或稀薄的。
曾经有人告诉我,你如何使用它才会有所不同!
我曾经使用StructureMap一个DI容器来解决一个问题,后来我重新设计了它来使用一个简单的工厂,并删除了对StructureMap的引用。
谁能告诉我它们之间的区别在哪里使用什么,这里的最佳实践是什么?
引用的大多数使用依赖注入的例子,我们也可以使用工厂模式来解决。看起来当涉及到使用/设计时,依赖注入和工厂之间的区别是模糊或稀薄的。
曾经有人告诉我,你如何使用它才会有所不同!
我曾经使用StructureMap一个DI容器来解决一个问题,后来我重新设计了它来使用一个简单的工厂,并删除了对StructureMap的引用。
谁能告诉我它们之间的区别在哪里使用什么,这里的最佳实践是什么?
当前回答
理论
这里有两点需要考虑:
谁创建对象:
[Factory]:你必须写如何创建对象。您有独立的Factory类,其中包含创建逻辑。 [依赖注入]:在实际情况下,这是由外部框架完成的(例如在Java中是spring/ejb/guice)。注入“神奇地”发生,无需显式地创建新对象。
它管理的对象类型:
[Factory]:通常负责有状态对象的创建 [依赖注入]:更可能创建无状态对象
关于如何在一个项目中同时使用工厂注入和依赖注入的实例
我们想要建造什么
用于创建包含多个名为orderline的条目的订单的应用程序模块。
体系结构
让我们假设我们想要创建以下分层架构:
域对象可以是存储在数据库中的对象。 存储库(DAO)帮助从数据库检索对象。 服务为其他模块提供API。允许对订单模块进行操作。
域层和工厂的使用
数据库中的实体是Order和OrderLine。Order可以有多个orderline。
现在是重要的设计部分。这个模块之外的模块是否应该自己创建和管理orderline ?不。只有当订单与之关联时,订单行才应该存在。最好能将内部实现隐藏到外部类。
但是如何在不了解OrderLines的情况下创建Order呢?
工厂
想要创建新订单的人使用了OrderFactory(它将隐藏关于我们如何创建订单的细节)。
这就是它在IDE中的样子。域包外部的类将使用OrderFactory而不是Order内部的构造函数。
依赖注入 依赖注入更常用于无状态层,如存储库和服务。
OrderRepository和OrderService由依赖注入框架管理。 存储库负责管理数据库上的CRUD操作。Service注入存储库并使用它来保存/查找正确的域类。
其他回答
我使用这两种方法来创建反转控制策略,为在我之后需要维护它的开发人员提供了更强的可读性。
我使用工厂来创建不同的层对象(业务,数据访问)。
ICarBusiness carBusiness = BusinessFactory.CreateCarBusiness();
另一个开发人员会看到这一点,当创建业务层对象时,他会在BusinessFactory中查看,智能感知会为开发人员提供所有可能创建的业务层。不需要玩游戏,找到我想要创建的界面。
这个结构已经是控制反转了。我不再负责创建特定的对象。但是您仍然需要确保依赖注入能够轻松地更改内容。 创建自己的自定义依赖注入是荒谬的,所以我使用Unity。在CreateCarBusiness()中,我要求Unity解决哪个类属于这个和它的生命周期。
所以我的代码工厂依赖注入结构是:
public static class BusinessFactory
{
public static ICarBusiness CreateCarBusiness()
{
return Container.Resolve<ICarBusiness>();
}
}
现在我两者兼得。我的代码对于其他开发人员来说也更易于阅读,因为我使用的对象的范围,而不是构造函数依赖注入,它只是说在创建类时每个对象都是可用的。
当我创建单元测试时,我使用它将我的数据库数据访问更改为自定义编码的数据访问层。我不希望我的单元测试与数据库、网络服务器、电子邮件服务器等通信。他们需要测试我的业务层,因为这是智能所在。
IOC is a concept which is implemented by two ways. Dependency creation and dependency injection, Factory/Abstract factory are the example of dependency creation. Dependency injection is constructor, setter and interface. The core of IOC is to not depend upon the concrete classes, but define the abstract of methods(say an Interface/abstract class) and use that abstract to call method of concrete class. Like Factory pattern return the base class or interface. Similariliy dependency injection use base class/interface to set value for objects.
简单来说,依赖注入和工厂方法分别意味着推和拉机制。
拉机制:类间接依赖于工厂方法,工厂方法又依赖于具体类。
推送机制:根组件可以在一个位置配置所有依赖组件,从而促进高维护和松耦合。
使用Factory方法时,创建新对象的责任仍然由类承担(尽管是间接的),而使用依赖注入时,责任是外包的(尽管是以泄露抽象为代价)。
当您确切地知道此时需要什么类型的对象时,就可以使用依赖项注入。而在工厂模式的情况下,你只是把创建对象的过程委托给工厂,因为你不清楚你需要什么类型的对象。
如果传递的参数可以在工厂中分组,那么它也是构造函数过度注入的一个很好的解决方案,看看下面的代码*):
public AddressModelFactory(IAddressAttributeService addressAttributeService,
IAddressAttributeParser addressAttributeParser,
ILocalizationService localizationService,
IStateProvinceService stateProvinceService,
IAddressAttributeFormatter addressAttributeFormatter)
{
this._addressAttributeService = addressAttributeService;
this._addressAttributeParser = addressAttributeParser;
this._localizationService = localizationService;
this._stateProvinceService = stateProvinceService;
this._addressAttributeFormatter = addressAttributeFormatter;
}
看看构造函数,你只需要在那里传递IAddressModelFactory,所以参数更少*):
public CustomerController(IAddressModelFactory addressModelFactory,
ICustomerModelFactory customerModelFactory,
IAuthenticationService authenticationService,
DateTimeSettings dateTimeSettings,
TaxSettings taxSettings,
ILocalizationService localizationService,
IWorkContext workContext,
IStoreContext storeContext,
ICustomerService customerService,
ICustomerAttributeParser customerAttributeParser,
ICustomerAttributeService customerAttributeService,
IGenericAttributeService genericAttributeService,
ICustomerRegistrationService customerRegistrationService,
ITaxService taxService,
CustomerSettings customerSettings,
AddressSettings addressSettings,...
你可以看到在CustomerController中传递了很多参数,是的,你可以看到这是构造函数的过度注入,但这就是DI的工作方式。CustomerController没有任何问题。
*)代码来自nopCommerce。