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

时间:2011-05-23 08:36:14

标签: php unit-testing dependency-injection dependencies

这是一篇由这篇文章组成的通用虚构示例。考虑6个班级

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

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

在此TableFactory中,无法拨打TableSchemaDBConnectlogger。我的目标是在外部范围内不需要的内部对象的例子。

TableData是内部提取并对数据进行操作,因此需要TableCrudDBConnectLogger

TableCrud包含TableSchema,需要DBConnectLogger

为了让事情变得有趣,

DbConnect itseld需要一个Logger。我的例子现在是3个范围深。

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

如果一个人尊重基本的OOP原则并且目标是易于测试 - >你会有外部对象需要注入5个对象,然后有getter方法来传递链上需要的对象。而内部范围的对象反过来又需要注入内部3范围深度对象的依赖关系,并为这些对象注入getter。这使得外部作用域对象需要很多依赖项,而getter只是为了传递它们。

这种对象传递方法是否有替代方法,我一路上错过了什么?请分享!任何链接/评论赞赏。

2 个答案:

答案 0 :(得分:47)

一种常见的误解是依赖关系需要通过对象图传递。总结MiškoHevery在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)。然后,您的构建器必须创建所有协作者,并确保将依赖项注入适当的对象。

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

答案 1 :(得分:1)

If you are stumbling upon the same question check Hervey's article that hits the bulls eye

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

In case the article vanishes in future here is the excerpt

"Every object simply knows about the objects it directly interacts with. There is no passing of objects reference just to get them into the right location where they are needed."

So what one need to do is instead of creating a deep nested object graph with passing the dependencies fro top to bottom, go horizontal and manage dependencies elsewhere.