依赖注入vs工厂模式

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

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

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

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

206371 次浏览

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

使用依赖注入框架,开发人员不需要手动准备和设置类实例的依赖项,这一切都是事先准备好的。

对于工厂,开发人员必须手工完成,并使用这些依赖对象创建类实例。

区别主要在于这一行中调用工厂并获取构造的对象,以及编写工厂方法来创建和设置所有内容(尽管可以认为,在依赖注入框架中,通过连接和配置对象关系,这也必须在一定程度上完成)。

然后对于工厂,你必须在任何需要这样一个对象的地方调用工厂。 使用DI框架,你主要可以依赖于在类实例创建时已经存在的对象

我的观点是,工厂方法更静态,因为它的实现相当固定,而依赖注入框架更动态,因为类实例的实际组合更容易改变(例如。为了测试目的)在运行时。

我相信DI是工厂的一种抽象层,但是它们还提供了抽象之外的好处。真正的工厂知道如何实例化单一类型并配置它。好的DI层通过配置提供实例化和配置多种类型的能力。

显然,对于具有一些简单类型的项目(在其构造中需要相对稳定的业务逻辑),工厂模式易于理解、实现并且工作良好。

OTOH,如果您有一个包含许多类型的项目,您希望经常更改这些类型的实现,DI通过其配置为您提供了在运行时执行此操作的灵活性,而无需重新编译工厂。

当使用工厂时,您的代码实际上仍然负责创建对象。通过DI,你可以将职责外包给另一个类或框架,这与你的代码是分开的。

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

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

IOC/DI本身就是领域对象和服务的完整生态系统。它以你指定的方式为你设置一切。域对象和服务是由容器构造的,而不是自己构造的:因此它们对容器或任何工厂都没有任何依赖。IOC/DI允许极高程度的可配置性,所有配置都集中在应用程序最顶层(GUI、Web前端)的一个地方(容器的构造)。

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

我相信DI是一种配置或即时化bean的方法。DI可以通过很多方式来实现,比如构造函数,setter-getter等等。

工厂模式只是实例化bean的另一种方式。此模式将主要用于必须使用工厂设计模式创建对象时,因为在使用此模式时,您不配置bean的属性,只实例化对象。

检查这个链接:依赖注入

Binoj,

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

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

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

我的想法:

依赖注入:将合作者作为参数传递给构造函数。 依赖注入框架:一个通用的、可配置的工厂,用于创建对象,并将其作为参数传递给构造函数

生命周期管理是依赖容器除了实例化和注入之外所承担的职责之一。容器在实例化后有时会保留对组件的引用,这就是它被称为“容器”而不是工厂的原因。依赖注入容器通常只保留对它需要管理生命周期的对象的引用,或者在未来的注入中重用的对象,如单例或flyweight。当配置为为容器的每次调用创建某些组件的新实例时,容器通常会忘记已创建的对象。

From: http://tutorials.jenkov.com/dependency-injection/dependency-injection-containers.html

我一读到DI的文章就有同样的问题,最后写了这篇文章。 最后,这就是我所理解的,如果我错了,请纠正我

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

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

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

IOC是一个概念,可通过两种方式实现。依赖创建和依赖注入,工厂/抽象工厂是依赖创建的例子。依赖注入是构造函数、setter和接口。IOC的核心是不依赖于具体的类,而是定义方法的抽象(比如接口/抽象类),并使用该抽象调用具体类的方法。像工厂模式一样返回基类或接口。类似地,依赖注入使用基类/接口来设置对象的值。

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

我知道这个问题很老了,但我想补充一下我的观点,

我认为依赖注入(DI)在很多方面类似于可配置的工厂模式(FP),从这个意义上说,你可以用DI做任何事情,你也可以用这样的工厂来做。

实际上,如果你使用spring为例,你可以选择自动装配资源(DI)或做这样的事情:

MyBean mb = ctx.getBean("myBean");

然后使用'mb'实例来做任何事情。这不是一个对工厂的调用,它将返回一个实例吗??

我注意到的大多数FP示例之间唯一真正的区别是,您可以在xml或其他类中配置“myBean”是什么,框架将作为工厂工作,但除此之外是一样的事情,您当然可以有一个工厂来读取配置文件或根据需要获得实现。

如果你问我的意见(我知道你没有),我相信DI做了同样的事情,但只是增加了开发的复杂性,为什么?

嗯,首先,为了让您知道用于DI自动装配的任何bean的实现是什么,您必须进入配置本身。

但是…您不必知道正在使用的对象的实现,这种承诺又如何呢?啐!严重吗?当你使用这样的方法时……你不就是写实现的那个人吗??即使你没有,你不是几乎所有的时间都在看如何实现它应该做什么??

最后一件事,依赖注入框架承诺了多少并不重要你将从它构建东西解耦,不依赖于他们的类,如果你使用一个框架,你将围绕它构建一切,如果你必须改变方法或框架,这将不是一项容易的任务……!…但是,由于您围绕特定的框架构建所有内容,而不是担心什么是最适合您的业务的解决方案,那么在这样做时,您将面临一个更大的问题。

事实上,我所能看到的FP或DI方法的唯一真正的业务应用是,如果你需要改变在运行时中使用的实现,但至少我所知道的框架不允许你这样做,你必须在开发时让所有的配置都完美无缺,如果你需要使用另一种方法。

因此,如果我有一个类,它在同一个应用程序的两个作用域中执行不同的操作(比如说,同一个公司的两个控股公司),我必须配置框架来创建两个不同的bean,并调整我的代码以使用每个bean。这是不是和我只是写这样的东西是一样的

MyBean mb = MyBeanForEntreprise1(); //In the classes of the first enterprise
MyBean mb = MyBeanForEntreprise2(); //In the classes of the second enterprise

和这个一样:

@Autowired MyBean mbForEnterprise1; //In the classes of the first enterprise
@Autowired MyBean mbForEnterprise2; //In the classes of the second enterprise

这:

MyBean mb = (MyBean)MyFactory.get("myBeanForEntreprise1"); //In the classes of the first enterprise
MyBean mb = (MyBean)MyFactory.get("myBeanForEntreprise2"); //In the classes of the second enterprise

在任何情况下,您都必须更改应用程序中的某些内容,无论是类还是配置文件,但您必须重新部署它。

这样做不是很好吗?

MyBean mb = (MyBean)MyFactory.get("mb");

通过这种方式,您可以设置工厂的代码以在运行时获得正确的实现,这取决于登录的用户企业??这很有帮助。您只需添加一个带有新类的新jar,并在运行时设置规则(或者如果您保留此选项,则添加一个新的配置文件),无需更改现有类。这将是一个动态工厂!

这不是比为每个企业编写两个配置,甚至为每个企业编写两个不同的应用程序更有帮助吗?

你可以告诉我,我不需要在运行时做切换,所以我配置应用程序,如果我继承类或使用另一个实现,我只是改变配置和重新部署。好的,工厂也可以做到这一点。说实话,你这样做过多少次了?也许只有当你有一个应用程序要在你公司的其他地方使用时,你要把代码传递给另一个团队,他们会这样做。但是,嘿,这也可以通过工厂来实现,如果使用动态工厂就更好了!!

不管怎样,评论区是开放的,你可以杀了我。

依赖注入

而不是实例化零件本身,一个car 的零件,它需要功能。

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的谷歌技术演讲非常棒,这是我得到我的例子的基础。# EYZ0

注入框架是工厂模式的实现。

这完全取决于你的要求。如果您需要在应用程序中实现工厂模式,那么您的需求极有可能由众多注入框架实现中的一个来满足。

只有在任何第三方框架都不能满足您的需求时,您才应该推出自己的解决方案。编写的代码越多,需要维护的代码就越多。代码是一种负债而不是资产。

关于应该使用哪个实现的争论没有理解应用程序的体系结构需求那么重要。

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

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

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

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

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

# EYZ0

工厂设计模式的特点是

  • 一个接口
  • 实现类
  • 一个工厂

当你这样问自己时,你可以观察到一些事情

  • 工厂什么时候为实现类创建对象——运行时还是编译时间吗?
  • 如果您想在运行时切换实现,该怎么办?- # EYZ0

这些是由依赖注入处理的。

依赖注入

您可以使用不同的方式注入依赖项。为了简单起见,让我们使用接口注入

在DI中,容器创建所需的实例,并将它们“注入”到对象中。

这样就消除了静态实例化。

例子:

public class MyClass{


MyInterface find= null;


//Constructor- During the object instantiation


public MyClass(MyInterface myInterface ) {


find = myInterface ;
}


public void myMethod(){


find.doSomething();


}
}
在我看来,使用依赖注入更好,如果你是: 1. 将代码部署在小分区中,因为它可以很好地解耦一个大代码。 2. 可测试性是DI可以使用的情况之一,因为你可以很容易地模拟非去耦的对象。通过使用接口,您可以轻松地模拟和测试每个对象。 3.你可以同时修改程序的每一部分,而不需要编码它的另一部分,因为它是松散解耦的

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

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

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

从表面上看,他们是一样的

用非常简单的术语来说,工厂模式,创建模式帮助我们创建一个对象-“定义一个创建对象的接口”。如果我们有一个键值类型的对象池(例如Dictionary),将键传递给工厂(我指的是简单工厂模式),您可以解析类型。完成工作! 依赖注入框架(如Structure Map, Ninject, Unity等)在另一方面似乎也在做同样的事情

但是…“不要白费力气”

从架构的角度来看,这是一个绑定层,“不要白费力气”。

对于企业级应用程序,依赖注入的概念更像是一个定义依赖关系的体系结构层。为了进一步简化,您可以将其视为一个单独的类库项目,它进行依赖解析。主应用程序依赖于这个项目,其中依赖项解析器引用其他具体实现和依赖项解析。

除了来自Factory的“GetType/Create”之外,我们通常还需要更多的特性(使用XML定义依赖关系、模拟和单元测试等)。由于您引用了结构映射,请查看结构图功能列表。这显然不仅仅是解决简单的对象映射。别白费力气了!

如果你只有一把锤子,那么所有东西看起来都像钉子

根据您的需求和您构建的应用程序类型,您需要做出选择。如果它只有很少的项目(可能是一个或两个..)并且涉及很少的依赖项,您可以选择一个更简单的方法。这就像使用ADO . net数据访问而不是使用实体框架进行简单的1或2个数据库调用,在这种情况下引入EF是多余的。

但是对于一个更大的项目,或者如果你的项目变得更大,我强烈建议有一个带有框架的DI层,并留出空间来改变你使用的DI框架(在主应用程序中使用Facade (Web应用程序,Web Api, Desktop..等)。

我认为,有3个重要方面支配着对象及其用法 1. 实例化(类的初始化,如果有).
2. 注射(这样创建的实例)在需要的地方 3.生命周期管理(这样创建的实例).
. 生命周期管理
使用Factory模式,实现了第一个方面(实例化),但其余两个方面有问题。使用其他实例的类必须是硬编码工厂(而不是正在创建实例),这阻碍了松耦合能力。此外,在工厂被用于多个地方的大型应用程序中,实例的生命周期管理成为一个挑战(特别是,如果工厂不管理它返回的实例的生命周期,它就会变得很难看)。

另一方面,使用DI (IoC模式),所有这3个都被抽象到代码之外(到DI容器),托管bean不需要这种复杂性。松散耦合,一个非常重要的建筑目标可以实现安静舒适。另一个重要的架构目标,分离关注点可以比工厂更好地实现。

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

理论

这里有两点需要考虑:

  1. 谁创建对象:
  • [Factory]:你必须写如何创建对象。您有独立的Factory类,其中包含创建逻辑。
  • [依赖注入]:在实际情况下,这是由外部框架完成的(例如在Java中是spring/ejb/guice)。注射“神奇地”发生了;无需显式地创建新对象。
  1. 它管理的对象类型:
  • [Factory]:通常负责有状态对象的创建
  • [依赖注入]:更可能创建无状态对象

关于如何在一个项目中同时使用工厂注入和依赖注入的实例

  1. 我们想要建造什么

用于创建包含多个名为orderline的条目的订单的应用程序模块。

  1. 体系结构

让我们假设我们想要创建以下分层架构:

enter image description here

域对象可以是存储在数据库中的对象。 存储库(DAO)帮助从数据库检索对象。 服务为其他模块提供API。允许对order模块进行操作
  1. 域层和工厂的使用
数据库中的实体是Order和OrderLine。Order可以有多个orderline。 # EYZ0 < / p >

现在是重要的设计部分。这个模块之外的模块是否应该自己创建和管理orderline ?不。只有当订单与之关联时,订单行才应该存在。最好能将内部实现隐藏到外部类。

但是如何在不了解OrderLines的情况下创建Order呢?

工厂

想要创建新订单的人使用了OrderFactory(它将隐藏关于我们如何创建订单的细节)。

enter image description here

这就是它在IDE中的样子。domain包外的类将使用OrderFactory而不是Order包内的构造函数。

    <李>依赖注入 依赖注入更常用于无状态层,如存储库和服务
OrderRepository和OrderService由依赖注入框架管理。 存储库负责管理数据库上的CRUD操作。

. Service注入知识库,并使用它来保存/查找正确的域类

enter image description here

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

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

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

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

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

如果传递的参数可以在工厂中分组,那么它也是constructor overinjection的一个很好的解决方案,看看这段代码*):

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中传递了很多参数,是的,你可以看到这是constructor overinjection,但这就是DI的工作方式。CustomerController没有任何问题。

*)代码来自nopCommerce。

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

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

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

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

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

我们使用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构造函数。问题在于:

  1. ParentChild的了解比它应该了解的要多
  2. Parent的合作者太多了
  3. Child添加依赖项需要更改Parent

这时我意识到Factory非常适合这里:

  1. 它隐藏了Child类的所有真实参数,如Parent所示
  2. 它封装了创建Child的知识,可以集中在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);
}
}

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

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

ICarBusiness carBusiness = BusinessFactory.CreateCarBusiness();

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

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

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

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

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

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

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

DI为您提供了根组成,这是连接对象图的单一集中位置。这往往使对象依赖关系非常显式,因为对象确切地要求它们所需要的东西,并且只有一个地方可以得到它。

组合根是一种清晰而直接的关注点分离。被注入的对象应该不依赖于DI机制,无论是第三方容器还是DIY DI。DI应该是不可见的。

工厂往往更加分散。不同的对象使用不同的工厂,工厂表示对象与其实际依赖关系之间的额外间接层。这个附加层将自己的依赖项添加到对象图中。工厂不是看不见的。工厂是一个中间商。

因此,更新工厂的问题更大:因为工厂是业务逻辑的依赖项,修改它们可能会产生连锁反应。组合根不是业务逻辑的依赖项,因此可以单独修改它。

GoF提到了更新抽象工厂的困难。他们的部分解释被引用在一个答案在这里中。将DI与工厂进行对比也与ServiceLocator是反模式吗?这个问题有很多共同之处

最终,选择哪个答案可能是固执己见的;但我认为这可以归结为一个工厂是一个中间人。问题在于,除了提供产品之外,这个中间商是否还能通过增加额外价值来发挥自己的作用。因为如果你能在没有中间商的情况下得到同样的产品,那为什么不把中间商去掉呢?

图表有助于说明区别。 # EYZ0 < / p >

(工厂)→有一个类根据请求参数创建类。毕竟,一个“工厂”;使“objects"在现实世界中也是如此。你可以让你的汽车供应商工厂生产(免费:)特斯拉。1给你。

(DI)→有一个(服务)容器存储接口(压缩类)。你不关心创建对象。你只需要让某个人/某个地方实现它,细节和其他东西对你、调用者或消费者都不重要。

DI是“D"坚定的原则。