代码之家  ›  专栏  ›  技术社区  ›  DavidWinterbottom

没有依赖注入的对象组合是件坏事吗?

  •  3
  • DavidWinterbottom  · 技术社区  · 15 年前

    当单元测试对象与另一个对象有一个合成关系(一个“HAS-A”关系)时,如我所理解的,如果您使用某种类型的依赖注入,则只能模拟组合对象。因此,以下类型的代码使得单元测试非常困难,因此可能被认为是一件坏事:

    <?php
    class aSampleClass {
        private $dependency;
        public function __construct() {
            $this->dependency = new otherClass;
        }
    }
    

    通过传递 otherClass 对象作为构造函数的参数,但情况并非总是如此。上述形式的对象组合(在类实现中直接使用“new”操作符)是不是一件坏事?您是否应该一直尝试编写一个类,以便能够在隔离其关联的情况下对其进行完全测试?

    当您使用简单的值对象(用领域驱动设计的术语来说)比如日期或货币对象时,使用依赖注入似乎会搁浅。在这些情况下,直接实例化所讨论的值对象似乎是有意义的。例如:

    <?php
        class anotherSampleClass {
            public function getTimeDifferencePhrase() {
                $now = new date_Time;
                $then = new date_Time(time()-60*60*24);
                return $now->relativeTimePhrase($then);
            }
        }
    

    当然,在这个例子中,对于 anotherSampleClass 同时执行 date_Time 对象,而不是尝试使用模拟对象或测试双重对象。

    思想?

    4 回复  |  直到 15 年前
        1
  •  2
  •   Mark Brackett Achilles Ram Nakirekanti    15 年前

    这取决于 什么 你在测试。依赖注入解决了测试类的问题,而不必担心它对外部服务的依赖性(这些服务可能会失败,没有测试数据,或者不适合单元测试)。

    你不会为了测试你的类是否正确地构造了一个值对象(或者一个字符串、int等等)并调用了difference操作符而模拟它……这都是实现的一部分,与测试它无关。

    但是,你要测试 getRelativeTimeDifferencePhrase 通过时正确返回“24小时前” 60 * 60 * 24 seconds .

    然后你会意识到你的硬编码 time() 导致一个脆弱的测试-因为你不能准确地预测什么 时间() 将在代码运行时返回。这将导致 RealTimeService 这将引入一个你可以控制的接缝。

    让你的类实例化 实时服务 会让你无法注射 MockTimeService -这样你就可以硬编码什么 时间() 是的,所以你最终会通过 ITimeService 给你的构造器。现在,你有依赖注入。;)

        2
  •  1
  •   Andreas Wallner    15 年前

    依赖注入确实解决了很多问题。然而,许多人没有看到它是一个集合而不是一个组合。在您实例化 其他类 你有一篇作文。因此,通过引入依赖注入,您实际上打破了demeter的组合和定律,引入了聚合。

    我认为依赖注入非常好,只要它不破坏体系结构。很多人说在构造函数中使用新运算符是不好的,应该将实例传递给构造函数,但是他们错了。它应该取决于域。有时甚至会导致混淆,特别是在没有垃圾收集的语言中。例如,C++中的经验法则是,创建者销毁一个对象。所以,如果有电池的手机被毁了,谁来销毁电池呢?是手机还是什么东西把它传给了手机?但在某些情况下,你会想把电池输入手机。例如,如果正在为工厂建模。

    所以,回答你的问题“没有依赖注入的对象组合是件坏事吗?”-这取决于你正在建模的领域,牺牲设计而不是可测试性在我看来是件坏事。如果你发现一些不稳定的东西,那么看看你的设计是否正确。我通常会看到是否可以引入依赖注入。如果这是不可能的,那么我看看我是否可以介绍工厂的方法。如果没有,我会看看我能不能做点别的。

        3
  •  0
  •   jrcalzada    15 年前

    在这些情况下,没有一个明确的规则可以遵循。依赖注入通常是件好事,但并不总是必要的。它是关于分析你的类,找出谁应该真正有责任创建依赖关系。

    如果您使用的是非常简单的对象,从语义上来说,这些对象属于您的类,并且您的类完全负责这些对象,那么依赖项注入可能过于工程化。你真的不需要测试日期时间,所以我不必费心注入那个特定的依赖项。

    另一件要考虑的事情是,在构造函数中构建依赖关系是否会使类不稳定。例如,在使用随机数生成器的类中会发生这种情况。在这种情况下,如果不使用依赖注入,就没有办法注入一个生成器,它将为您提供一组适合测试的可预测数字。

    所以,简短的回答是:这通常是件好事,但绝不总是必要的。

        4
  •  0
  •   pondermatic    15 年前

    对于这样的事情没有硬性规定。一些纯粹主义者会说你应该注入依赖性,而其他人则会选择更务实的方法。由于vo本身没有任何依赖关系,我可能会调用kiss原则,并说在对象中“新建”它是完全可以的。尤其是vo驻留在同一个模块中(用ddd术语来说),而且,在对象中实例化vo并不会降低它的可测试性。