gpt4 book ai didi

php - 依赖重载而不是依赖注入(inject)?

转载 作者:可可西里 更新时间:2023-10-31 22:48:20 25 4
gpt4 key购买 nike

我将以简短的问题开头作为长问题的开头:

问题的简短版本

允许对象实例化其自己的依赖关系,然后提供构造函数参数(或setter方法)以简单地覆盖默认实例化,这是怎么回事?

class House
{
protected $door;
protected $window;
protected $roof;

public function __construct(IDoor $door = null, IWindow $window = null, IRoof $roof = null)
{
$this->door = ($door) ? $door : new Door;
$this->window = ($window) ? $window : new Window;
$this->roof = ($roof) ? $roof : new Roof;
}
}

问题的长版

我提出这个问题的动机是,依赖注入(inject)要求您跳过障碍,仅向对象提供所需的对象。 IoC容器,工厂,服务定位器.....所有这些都引入了许多其他类和抽象,这些类和抽象使您的应用程序的API变得复杂,我认为,在许多情况下,测试同样困难。

对象实际上知道它需要什么依赖关系才能正常运行,这不是逻辑吗???

如果依赖项注入(inject)的两个主要动机是代码的可重用性和单元可测试性,那么能够用 stub 或其他对象覆盖默认实例就可以了。

同时,如果您需要在应用程序中添加房屋类,则只需编写房屋类代码,而无需在其上添加工厂和/或DI容器。此外,任何利用房屋的客户端代码都可以只包含房屋,而无需从上方的某个地方获得房屋工厂或抽象服务定位器。一切变得非常简单,没有中间人代码,仅在需要时实例化。

我是否完全不认为某个对象具有依赖项,它应该能够自己加载它们,同时提供一种机制,可以根据需要使这些依赖项过载?

示例
#index.php (front controller)

$db = new PDO(...);
$cache = new Cache($dbGateway);
$session = new Session($dbGateway);
$router = new Router;

$router::route('/some/route', function() use ($db, $cache, $session)
{
$controller = new SomeController($db, $cache, $session);
$controller->doSomeAction();
});



#SomeController.php

class SomeController
{
protected $db;
protected $cache;
protected $session;

public function __construct(PDO $db, ICache $cache, ISession $session)
{
$this->db = $db;
$this->cache = $cache;
$this->session = $session;
}

public function doSomeAction()
{
$user = new \Domain\User;
$userData = new \Data\User($this->db);

$user->setName('Derp');
$userData->save($user);
}
}

现在,在一个具有许多不同模型/数据类和 Controller 的大型应用程序中,我感觉不得不将DB对象传递给每个 Controller (不需要它),而只是将其提供给每个数据映射器(需要使用它)。它),有点臭。

通过扩展,通过 Controller 传递服务定位器或DI容器,只是为了定位数据库,然后每次将其提供给datamapper,这似乎也有些臭味。

将工厂或抽象工厂传递给 Controller ​​,然后不得不通过诸如 $this->factory->make('\Data\User');之类的笨拙实例化新对象似乎也很尴尬。尤其是因为您需要编码抽象工厂类,所以实际工厂将为您想要的对象关联依赖关系。

最佳答案

您的问题问得很好,我非常喜欢人们出于“单元测试和可维护性”的原因质疑常识(无论您是哪个程序员,如果您不这样做,它们都是坏程序员) -it-topics,它总是与单元测试和可维护性有关。因此,您在这里提出了一个正确的问题:DI确实支持单元测试和可维护性吗?并预料到:如果使用正确,它会...

关于分解

依赖注入(inject)(DI)和控制反转(IoC)是机制,它们增强了封装和分离OOP关注点的核心概念。因此,要回答这个问题,就必须争论为什么封装和分离关注点是一件很酷的事情。两者都是分解的核心机制:封装(是的,我们有模块)和关注点分离(并且在某种意义上有模块)。关于这个话题可以写很多东西,但是就目前而言,要说它是关于降低复杂性就足够了。系统的分解使您可以将系统(无论多大)分解为人脑能够管理的部分。尽管有点哲理,但这确实很重要:如果人脑没有局限性,那么整个可维护性主题就不会那么重要。好的,让我们说:分解是一种将系统的感知复杂性降低为我们可以管理的块的技巧。

但是,与往常一样,它要付出代价:分解也增加了复杂性,就像您对DI所说的那样。仍然有意义吗?是的,因为:

人为增加的复杂度与系统的固有复杂度无关。

基本上就是抽象的水平。它的含义是:您需要根据要构建的系统的固有复杂性(或一天可能达到的复杂性)来选择分解的程度和实现该分解所花费的精力。

与DI一起分解

特别是关于DI:根据以上所述,存在足够小的系统,其中DI的增加的复杂性不能证明降低的感知复杂性是合理的。而且,不幸的是,网络上的每个教程都涉及其中之一,这不支持理解整个绒毛的含义。

但是,大多数(或至少许多)现实生活项目都达到了固有的复杂性程度,因此在附加分解上的投资得到了充分的利用,因为降低了感知的复杂性可以加快后续开发的速度并减少错误。依赖注入(inject)是做到这一点的技术之一:

DI支持将What(接口(interface))和How(实现)分开:如果仅关于玻璃门,我同意:如果这对于一个人的大脑来说太多了,那么他(她)可能就不应该成为程序员。但是现实生活中的事情更加复杂:DI使您可以专注于真正重要的事情:作为一所房子,只要我可以依靠它可以关闭和打开的事实,我就不在乎我的门。也许现在没有门了?您现在根本不需要关心。将组件注册到您的容器中时,您可以再次关注:我要在我家中的哪扇门上?您不再需要关心门或房屋本身:它们很好,您已经知道了。您已经将关注点分开了:事物如何组合在一起(组件)以及实际上如何将它们组合在一起(容器)的定义。根据我的经验,仅此而已。听起来很笨拙,但在现实生活中,这是一个了不起的成就。

少一些哲学

为了使它重新 Root ,有许多更实际的优点:

随着系统的发展,总有一些尚未开发的部分。在大多数情况下,指定行为要比实现行为少得多的工作。没有DI,只要没有门被开发就无法开发房屋,因为没有可实例化的东西。使用DI,您无需担心:您只需使用界面设计房屋,就可以针对这些界面使用模拟程序编写测试,并且还可以:您的房屋可以正常工作,甚至不存在 window 和门。

您可能知道以下几点:您已经为某件事工作了几天(让我们说一扇玻璃门),您为此感到自豪。六个月后-在此期间您学到了很多东西-再次查看它,这很废话。你把它扔掉。如果没有DI,则需要更改房屋,因为它使用的是您刚刚废弃的类。有了DI,您的房子就不会改变。它可能位于它自己的程序集中:您甚至不需要重新编译内部程序集,它就不会受到影响。在复杂的情况下,这是一个巨大的优势。

还有更多,但也许考虑到所有这些,当您下次阅读DI的好处时,更容易想象DI的好处...

关于php - 依赖重载而不是依赖注入(inject)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19504781/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com