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

Posted

技术标签:

【中文标题】依赖地狱——如何将依赖传递给深度嵌套的对象?【英文标题】:Dependency Hell — how does one pass dependencies to deeply nested objects? 【发布时间】:2011-08-30 23:40:02 【问题描述】:

这是为这篇文章制作的一个通用的虚构示例。考虑 6 个类

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

TableFactory 是外部类,假设它包含一个 DB 表的 TableData 对象。

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

TableData是对数据的内部获取和操作,所以需要TableCrudDBConnectLogger

TableCrud 包含TableSchema 并需要DBConnectLogger

DbConnectitseld,为了让事情变得有趣,需要一个 Logger。我的示例现在是 3 个作用域深度。

我的问题很简单,如果您有一个对象 3(或更多)范围内的对象不被外部范围内的对象调用,如何在不破坏接口的情况下将这些对象从外部范围发送到内部范围隔离原则 -> TableFactory 不应该处理内部对象所需的 DBConnect 或 Logger。

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

这种对象传递方法是否有替代方法,我在此过程中错过了一些东西?请分享!任何链接/cmets 表示赞赏。

【问题讨论】:

【参考方案1】:

如果您遇到同样的问题,请查看 Hervey 的文章,该文章中了靶心

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

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

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

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

【讨论】:

【参考方案2】:

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

class HouseBuilder

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

        return $house;
    

如您所见,House 完全没有意识到其中的门需要锁。 HouseBuilder 负责创建所有必需的依赖项并根据需要将它们堆叠在一起。由内而外。

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

另见How to Think About the “new” Operator with Respect to Unit Testing

【讨论】:

戈登 --> 你太棒了! ;) 谢谢伙计,如果你来蒙特利尔,我欠你一杯啤酒,因为你一直在暗示我!反正你不需要业力。 @stef 不客气。不确定我明年是否会参加 Confoo,但如果我参加了,我会很高兴和你一起喝啤酒;)

以上是关于依赖地狱——如何将依赖传递给深度嵌套的对象?的主要内容,如果未能解决你的问题,请参考以下文章

如何将 BuildConfig 值传递给依赖模块?

我应该如何将依赖项传递给我的类?

Gradle - 排除嵌套的传递依赖

如何解决 Maven/Gradle 中的多级间接缺失依赖地狱?

如何通过某些依赖注入来限制对象创建?

使用 Maven 处理依赖地狱的系统方法