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


Dependency Hell — how does one pass dependencies to deeply nested objects?

下面是为本文编写的一个通用假想示例。考虑6类

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

TableFactory是外部类,假设它为DB表保存一个TableData对象。

在该TableFactory中,不存在对TableSchemaDBConnectlogger的调用。我的目标是一个在外部范围内不需要的内部对象的例子。

TableData是一个内部获取和操作数据,因此它需要TableCrudDBConnectLogger

TableCrud包含TableSchema并且需要DBConnectLogger

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

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

如果一个人尊重OOP的基本原则并以易于测试为目标->您将有需要注入5个对象的外部对象,然后有getter方法,可以将所需的对象进一步传递到链上。内部作用域对象反过来需要注入其内部3作用域对象的依赖项,并为这些对象注入getter。这使得外部范围的对象需要许多依赖项,而getter只是为了传递这些依赖项

有没有一种替代这种对象传递方法的方法,这是我一路上错过的?请分享!欢迎任何链接/评论。

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

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

正如你所看到的,豪斯完全没有意识到里面的门需要锁。HouseBuilder负责创建所有必需的依赖项,并根据需要将它们堆叠在一起。由内而外。

因此,在您的场景中,您必须确定哪些对象应该对哪些依赖项进行操作(参见德米特定律)。然后,您的Builder必须创建所有协作者,并确保将依赖项注入到适当的对象中。

另请参阅如何考虑单元测试方面的"新"操作员

如果你偶然发现了同样的问题,请查看Hervey的文章

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

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

"每个对象都只知道它直接交互的对象。没有传递对象引用,只是为了把它们放在需要的正确位置。"

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