3

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

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

即具有服务的默认后备类类型的概念

4

1 回答 1

3

这种模式会起作用(事实上,(反)模式有一个名字- Bastard Injection),但是这种方法存在一些问题:

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

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

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

  4. 如果您的依赖项本身还有其他依赖项,这些依赖项也使用构造函数注入,那么默认构造路径很快就会变得笨拙,并导致更多的耦合,因为您现在需要完成所有艰苦的工作来解决您的 IoC 容器为您完成的依赖项,例如

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

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

于 2012-08-24T09:59:29.217 回答