使用构造函数依赖项注入时,为依赖项提供回退/缺省值?

时间:2012-08-24 09:54:16

标签: oop dependency-injection

使用依赖注入时这是不是很糟糕:

public function __construct($service = null)
{
    if(null === $service){
        $service = MyNewDefaultService()
    }
    $this->service = $service;
}

即。具有服务的默认回退类类型的概念

1 个答案:

答案 0 :(得分:3)

这种模式可行(事实上,(反)模式有name - Bastard Injection),但是这个方法存在一些问题:

  1. 通过在您的使用者类中构建新的MyNewDefaultService()依赖项,除了抽象之外,您还要耦合到具体的服务类。在编译语言中,这也意味着您的消费代码现在需要对包含具体依赖类的jar / library / dll / assembly进行硬“引用”,而如果省略直接构造,则可以仅在接口上进行耦合。在脚本语言中,您需要确保在运行时可以解析具体的依赖关系。

  2. 依赖关系MyNewDefaultService的生命周期管理现在硬编码为与消费类的生命相同。由IoC容器注入和管理的对象的Lifespans可以为您提供更多的灵活性(例如,注入共享对象等)。

  3. 测试现在变得更加复杂,因为您无法模拟“默认”路径(即$service == null时),因此您需要混合单元测试(对于注入路径,具有模拟依赖性) )和集成测试(针对默认路径)来证明代码的正确性。

  4. 如果您的依赖项本身还有其他依赖项,它们也使用构造函数注入,那么默认构造路径很快就变得难以处理,并导致更多耦合,因为您现在需要完成所有努力解决IoC的依赖项容器会为你做的,例如

  5. if(null === $service){
        $service = MyNewDefaultService(RepoFactory.Create(LoggerFactory.Create()), ...)
    }
    

    TL; DR 虽然当您从耦合层次结构迁移到由IoC容器管理的松散耦合的依赖注入层次结构时,此方法在瞬态阶段可能很有用,但是真正的好处是Dependency Inversion Principle只有在构造函数只有一条路径时才能完全实现,即通过将抽象耦合到所有依赖项,而不是任何具体的实现。