依赖性地狱 - 如何将依赖关系传递给深度嵌套的对象?

这是为这篇文章编造的一个通用的虚构例子。考虑 6 类

TableFactory, TableData, TableCRUD, TableSchema, DBConnect, Logger. 

TableFactory是外部类,假设它保存数据库表的对象。TableData

在此,没有对 或 的调用。我的目标是一个外部范围中不需要的内部对象的示例。TableFactoryTableSchemaDBConnectlogger

TableData是一个内部抓取并对数据进行操作,因此它需要 和 。TableCrudDBConnectLogger

TableCrud包含 和 需要 和 。TableSchemaDBConnectLogger

DbConnectitseld,为了让事情变得有趣,需要一个Logger。我的例子现在是3个范围深度。

我的问题很简单,如果你有一个对象3(或更多)作用域,而外部作用域上的对象没有调用,那么如何在不违反接口隔离原则的情况下将这些对象从外部作用域发送到内部作用域 - >TableFactory不应该处理内部对象所需的DBConnect或Logger。

如果一个人尊重基本的OOP原则,并致力于易于测试 - >你就会有外部对象需要注入5个对象,然后有getter方法将所需的对象传递到链的更远的地方。而内部作用域对象反过来又需要注入其内部 3 作用域深对象的依赖项,这些对象也需要 getter。这使得外部作用域对象需要许多依赖项,而 getter 只是为了传递这些依赖项。

除了这种对象传递方法之外,有没有另一种选择,这是我一路上错过的?请分享!任何链接/评论赞赏。


答案 1

一个常见的误解是,依赖关系需要通过对象图传递。总结一下Miško Hevery在Clean Code中给出的例子:不要寻找东西,一个需要门的房子,不需要知道门锁:

class HouseBuilder
{
    public function buildHouse()
    {
        $lock  = new Lock;
        $door  = new Door($lock);
        $house = new House($door);

        return $house;
    }
}

正如你所看到的,豪斯完全忘记了门需要锁的事实。HouseBuilder负责创建所有必需的依赖项,并在需要时将它们堆叠在一起。由内而外。

因此,在您的方案中,您必须确定哪些对象应该对哪些依赖项进行操作(参见 Demeter 定律)。然后,您的构建器必须创建所有协作者,并确保将依赖项注入到相应的对象中。

另请参阅如何考虑单元测试方面的“新”运算符


答案 2

如果您偶然发现相同的问题,请查看Hervey的文章,该文章击中了靶心

http://misko.hevery.com/2008/10/21/dependency-injection-myth-reference-passing/

如果文章将来消失,这里是摘录

“每个物体都知道它直接与之交互的物体。没有传递对象引用只是为了将它们放到需要它们的正确位置。

因此,人们需要做的是,不要创建一个深度嵌套的对象图,从上到下传递依赖关系,而是水平移动并管理其他地方的依赖关系。


推荐