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