依赖注入或服务定位器 - Symfony

时间:2014-10-10 17:19:13

标签: symfony dependency-injection service-locator

我已经开始通过Symfony2代码,研究了一些像Pimple这样的小班,经过几个小时的考试后出现了奇怪的想法。最好的开始是解释我如何理解一些术语,所以:

依赖 另一件事需要的东西,比如"引擎"在" car"

容器 能够存储许多其他对象的对象或类,例如" engine","变速箱"甚至" car"

依赖注入 将每个依赖项注入对象的过程,如果我需要" car"我知道我必须注射"引擎","变速箱"还有很多其他的东西。重要的是," car"不要创造"引擎",但"引擎"放在" car"

服务定位器 对象要求另一个对象的过程,例如进入汽车时插入我们的容器,当汽车需要启动它需要从容器"引擎",所以容器返回他"引擎&#34 ;

当我研究Symphony代码时,他们从依赖注入开始,但过了一段时间我意识到当创建Controller时,会注入整个容器然后你可以使用$ this-> get(' serviceName&# 39;)得到它,所以它看起来更像服务定位器,根据少数文章是反模式。

播种怎么回事? DI和SL之间的界限是否很小,有时会破坏?还是我误解了什么?如果我使用DI,我是否需要将每个服务插入控制器,所以我从外面知道我使用的是什么?或者控制器在某些情况下可以容器?

1 个答案:

答案 0 :(得分:10)

您对DI的理解非常好。是的, Symfony Controller 确实实现了ContainerAwareInterface,正如您所说,它具有服务定位器角色。但服务定位器不是一种反模式。每种模式都有正确和不正确的用途。

此外,Symfony不以任何方式强制您使用它的控制器。您的控制器can be a service。地狱,它甚至可以是一个功能!

以下是控制器作为服务定位器实施的原因之一:效果

让我们放下汽车类比并关注99%的项目中您遇到的真实情况:您需要CRUD资源。我们假设您正在构建 Todo 应用,并且您需要一个RESTfulish控制器来处理任务资源的CRUD操作。

您需要的最少的是阅读所有任务的方法和添加新任务的方法,因为您需要两个操作:索引(通常命名为 list 也是)和商店(通常也称为创建)。

Symfony中的常见流程是伪代码:

indexAction -> getDoctrine -> getTaskRepository -> getAllTasks

storeAction -> getFormFactory -> createForm -> bindRequestDataToForm -> getDoctrine -> saveData

如果Controller是服务定位器

索引操作

执行索引操作时,只有将从容器解析的服务才会是 ManagerRegistry (在本例中为 Doctrine 服务)。然后我们会要求它给我们任务库,我们将用它来完成我们的操作。

商店行动

当执行商店操作时,我们会做更多的工作:让容器给我们 FormFactory ,用它做一些操作,然后让它给它我们 Doctrine 也可以用它做一些操作。

总结:当执行索引操作时,服务容器只需构造一个服务,执行更新时,必须构造两个服务。

如果Controller是常规服务

让我们看看控制器需要什么。从上面的部分可以看出,它需要 FormFactory Doctrine

现在,当您只想调用索引操作从数据存储中读取所有任务时,控制器必须通过容器实例化。在可以实例化之前,容器需要实例化它的依赖关系:FormFactory和Doctrine。然后在将这两个注入控制器的同时实例化控制器。

因此,您正在调用索引操作,根本不需要 FormFactory ,但您仍然需要创建它的开销,因为操作需要它在该请求中根本不会被调用。

懒人服务

为了减少这种开销,有一个名为lazy service的东西。它的工作原理是将服务的代理实际注入控制器。所以,就控制器而言,它有 FormFactory 。它不知道的是,它不是真正的 FormFactory,而是一个伪对象,它会在你调用某个方法时将调用委托给真正的 FormFactory 代码它

将其包装

控制器不一定是服务定位器,但也可以。使其成为服务定位器可以更高效,更容易引导,但隐藏依赖性。此外,测试起来有点困难,因为您需要模拟依赖容器。无论您是想制作控制器服务,功能还是服务定位器,Symfony都不会强制您使用这些方式。

根据我的经验,只要您不在其中编写业务逻辑,扩展默认 Symfony控制器并让控制器成为服务定位器就好了,而是将所有工作委托给您从容器获得的服务。这样,你很可能不会在控制器代码中出现错误(因为方法通常包含2-3行代码),并且可以在不进行测试的情况下离开。