【问题标题】:Service Locator, Dependency Injection (and Container) and Inversion of Control服务定位器、依赖注入(和容器)和控制反转
【发布时间】:2012-04-06 22:25:58
【问题描述】:

我已经编程了一段时间,但从来没有兴趣从理论上了解每个概念的含义,我可能会使用各种编程概念,但并不知道。

服务定位器: 对我来说,是指通过减少代码量来加速开发的捷径记录。一个问题是:Locator 可以只引用命名空间/类,还是我可以拥有一个变量注册表?

这是我的理解:

$locator = new ServiceLocator()
$locator->set('app', new System\Application());
$locator->set('db', new System\Pdo());

// Get the objects
$locator->get('db')->connect();
$locator->get('app')->run();

依赖注入(和依赖注入容器): 在对象中注入对象,无论工厂模式如何,都可以更快地访问这些对象。还有 DI 容器?

这是我的理解:

$app = new System\Application(System\Config::load());

控制反转: 不懂这个设计模式(或者懂但不知道我做的是不是IoC)

那么,在理论上(最好有简单的例子),这些概念中的每一个是什么意思?我是正确的,还是有什么问题/可以改进?

谢谢!

【问题讨论】:

  • 不确定您所说的“访问速度更快”是什么意思。全局变量或单例也一样快。我认为您所说的更多是关于模块化。
  • 当我有一个 DI 时,整个类被注入到另一个类中,所以,我不需要另一个设计模式,因为我在我的第二类中拥有了我需要的一切。 (明白吗?!)
  • 等一下......谁在这里问问题? :P
  • 我将您的评论解释为一个问题。 (巴西初学者的东西)。你在谈论什么模块化? DI、IoC和service Locator跟这个有关系吗,能多解释一下吗?
  • 将注入视为松散耦合的一种形式。不同的模块不必“知道”如何相互访问,但您可以注入引用。这使得在不破坏您忘记的东西的情况下更改不同的模块变得更加容易。为了代码的可持续发展,它是一种模块化方法,而不是访问方便。

标签: php design-patterns dependency-injection inversion-of-control service-locator


【解决方案1】:

Service Location and Dependency Injection 首先是为了解耦类,以便于测试和更改它们。

当您将 IoC 容器registerresolve 部分与 Service Locator 进行比较时, >似乎是一样的。

您可以将 IoC 容器用作服务定位器,这被​​认为是一种反模式。当您使用服务定位时,您总是必须在整个架构中主动调用服务定位器。因此,您将类解耦,但另一方面,您将它们全部耦合到服务定位器。此外,使用服务定位器发现依赖关系更加困难,因为您隐藏了依赖关系。而使用依赖注入,您可以使用构造函数注入将依赖项“公开”。

当您使用 IoC 容器时,您会使用依赖注入(构造函数注入或属性注入)。 IoC 容器现在能够通过查看构造函数参数来解析依赖关系图并创建整个依赖关系图。这称为自动连接。服务定位器无法自动连接依赖项。 正如我已经提到的,您不必强制使用自动连接,您可以通过简单地直接在每个类中调用 IoC 容器来轻松使用 IoC 容器,就像服务定位器一样,但你不应该

另请参阅:https://stackoverflow.com/a/11319026/175399

【讨论】:

  • 我完全不了解 IoC。您可以发布一些示例吗?
  • @GabrielSantos 我只能发布 .NET 的示例。
  • 感谢@Rookian,但不懂.NET =P
  • 老实说,我有类似的问题 - 我得到了服务定位器(反模式),我想我理解 DI,但从我的角度来看,IoC 要么是 DI,要么是服务定位器 - 取决于它的使用方式。从我的角度来看,它是由可能的实现组成的 IoC 组:Service Locator OR DI ...你仍然觉得提供他们......谢谢! ;-)
  • @shadyyx 完全正确。这有点令人困惑,因为人们习惯说 DI 容器或 IoC 容器。该框架是一个 IoC 容器,主要用作 DI 工具。就个人而言,我倾向于称它为 DI 容器 :)
【解决方案2】:

我认为您正确理解了服务定位器。

关于依赖注入,意思是如果一个对象有构造函数和/或属性依赖,这些是由外部注入到对象中的,而不是对象自己获取依赖

public class MyClass
{
   private $_dep;
   public function __construct($dep=null)
   {
       //$dep has to be injected
       $this->_dep=$dep;                           
   }

   //this is wrong because it couples MyClass to a specific Dependency implementation
   public function __construct()
   {
       $this->_dep=new Dependency();
    }
}
   $dep=new Dependency();
   $obj=new MyClass($dep);

通常构造函数将抽象(一个接口)作为参数,并在类外部实例化一个具体实现,然后在创建 MyClass 的新实例时将其传递给构造函数。

一个 DI 容器,自动处理依赖注入。您只需对其进行配置,以便它知道在询问抽象时要返回哪些具体类。容器处理对象创建,通过构造函数和/或属性注入依赖项。根据容器(我不知道 php 的示例,我只熟悉 .net DI 容器),您可能还必须注册可以由 它。

控制反转意味着不是较高级别的类依赖于较低级别的类(依赖)实现,而是控制被反转,因此较低级别的类实现依赖于较高级别所需的抽象等级类。

//abstraction defined for the use of higher level class
public interface  IRepository {}

// that's the dependency, the lower level class  
public class XmlRepository implements IRepository {}

//the higher level class
 public class MyClass
 {
     public function __construct(IRepository $repo) {}
  }

IoC 和 DiC 结合在一起,因为 DI 容器提供了 IoC 功能。

【讨论】:

  • 很好的解释。那么,DI 谈论注入一个对象并存储在您注入的类中,以允许将来访问?
  • 关于IoC,不太了解,如果能多解释,谢谢。
  • 关于 DI,是的。关于 IoC,我不知道如何更好地解释它,但是每次一个类指定它需要一个抽象作为依赖时,这就是 IoC 模式。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-01-21
  • 1970-01-01
  • 2012-02-05
  • 1970-01-01
  • 1970-01-01
  • 2010-10-31
相关资源
最近更新 更多