哪个更好:依赖注入+注册表或依赖注入或全局注册表?
首先,我想将这个问题仅限于Web开发。因此,只要该语言用于Web开发,这就是与语言无关的。就个人而言,我是从PHP的背景来的。
通常,我们需要使用来自多个作用域的对象。例如,我们可能需要在正常范围内使用数据库类,但也需要在控制器类中使用数据库类。如果我们在正常范围内创建数据库对象,则无法从控制器类内部访问它。我们希望避免在不同的作用域中创建两个数据库对象,因此需要一种重用数据库类的方法,而不管作用域如何。为此,我们有两种选择:
- 使数据库对象成为全局对象,以便可以从任何位置访问它。
- 例如,将数据库类以参数的形式传递给控制器的构造函数。这称为依赖关系注入 (DI)。
当有许多类涉及许多不同作用域中所有要求苛刻的对象时,问题变得更加复杂。在这两种解决方案中,这都会成为问题,因为如果我们使每个对象都是全局的,那么就会将太多的噪声放入全局范围,并且如果我们向类传递太多参数,则该类将变得更加难以管理。
因此,在这两种情况下,您经常会看到注册表的使用。在全局情况下,我们有一个注册表对象,该对象被设置为全局,然后将所有对象和变量添加到该对象中,使它们在任何对象中都可用,但只将单个变量(注册表)放入全局范围。在 DI 情况下,我们将注册表对象传递到每个类中,将参数数减少到 1。
就个人而言,我使用后一种方法,因为许多文章主张它而不是使用全局变量,但我遇到了两个问题。首先,注册表类将包含大量的递归。例如,注册表类将包含数据库类所需的数据库登录变量。因此,我们需要将注册表类注入到数据库中。但是,许多其他类将需要该数据库,因此需要将数据库添加到注册表中,从而创建一个循环。现代语言可以很好地处理这个问题,还是会导致巨大的性能问题?请注意,全局注册表不会受到此影响,因为它不会传递到任何内容中。
其次,我将开始将大量数据传递给不需要它的对象。我的数据库不关心我的路由器,但路由器将与数据库连接详细信息一起传递到数据库。通过递归问题使情况变得更糟,因为如果路由器具有注册表,注册表具有数据库和注册表,并且注册表被传递到数据库,则数据库通过路由器传递给自身(即,我可以从数据库类内部执行”)。$this->registry->router->registry->database
此外,除了更复杂的之外,我没有看到DI给我带来了什么。我必须将一个额外的变量传递到每个对象中,并且我必须使用注册表对象而不是.现在,这显然不是一个大问题,但如果它没有给我任何关于全球方法的东西,它似乎确实是不必要的。$this->registry->object->method()
$registry->object->method()
显然,当我在没有注册表的情况下使用DI时,这些问题并不存在,但是我必须“手动”传递每个对象,从而导致类构造函数具有荒谬的参数数量。
考虑到两个版本的 DI 都存在这些问题,全局注册表不是更优越吗?通过对 DI 使用全局注册表会丢失什么?
在讨论DI与Globals时经常提到的一件事是,全局变量会抑制您正确测试程序的能力。全局变量究竟如何阻止我测试 DI 无法测试的程序?我在很多地方读到过,这是因为全局可以从任何地方改变,因此很难被嘲笑。但是,在我看来,由于至少在PHP中,对象是通过引用传递的,因此在某个类中更改注入的对象也会在注入它的任何其他类中更改它。