2011-02-07 21 views
1

我偶然发现了一些代码,我很好奇为什么它会这样。构造具有函数作为依赖注入手段的对象

有两个构造函数,主要是在代码中调用,第二个是在依赖注入测试中使用。第二个构造函数接受一个返回对象的函数,而不是对象本身的一个实例。

MainConstructor() 
:this(() => Factory.Current.GetInstance<IQueryService>()){ 
} 

SecondConstructor(Func<IQueryService> getQueryService){ 
} 

我很好奇你会从传递函数而不是实例中获得好处。

+1

什么是一种奇怪的方式来做依赖注入。 – Snowbear 2011-02-07 19:11:13

回答

1

有做这样的事情几种可能的好处:

  1. 脱钩:通过允许呼叫者委托传递,而不是一个实例,无论是主叫用户和被叫(在你的案例正在构建的类)可以从传递的对象和它来自的地方分离。
  2. 懒惰收购:通过传递委托,可以以懒惰的方式获取实例。换句话说,构造函数原则上可以缓存委托并在最后可能的时刻调用它,只有当实际需要实例时才会调用它。如果实例从不需要,它可能永远不会被创建。
  3. 可重复性:通过传递委托而不是实例,该类可以缓存用于按需创建查询服务的机制。通过这种方式,代表充当工厂,允许按需创建所需类型的实例。
0

使用Func<T>允许延后创建产品,它是可选的依赖关系非常有用 - 例如在类中的方法之一可能是这样的:

public void SomeMethod() 
{ 
    if(someCondition) 
    { 
     IQueryService service = this.getQueryService(); 
     service.Execute(): 
    } 
} 

如果IQueryService是昂贵的创建这可以提高工作效率如果someCondition从未评估为真。

0

Func<IQueryService>在这种情况下真的是变相的抽象工厂。所以问题的确是:“你为什么要使用工厂而不是注入对象本身?”

您在使用工厂时,此类实例的生命周期对消费者而言很重要,您需要控制该实例的生命周期,或者该实例的创建成本很高。很好的例子是当对象实现IDisposable。一次性物品通常需要明确控制。

我个人不喜欢使用Func<T>代表作为工厂,因为它使您的代码更加清晰。而不是根据Func<IQueryService>,让班级依赖于IQueryServiceFactory。这使得你的代码更加明确。这种方法的缺点当然是你将不得不编写更多的代码(不多,但仍然)。

第二个构造函数使用依赖注入模式。然而,第一个构造函数是Poor Man's DI的示例。这是一种允许为单元测试注入依赖关系的方式,但是可以节省您为生产代码使用依赖注入框架的需求。这种方法的缺点是需要依赖容器(在您的案例中为Factory),这种模式称为Service Locator。另一个缺点是它使一个类所需的依赖性不太明显。

相关问题