开发者

Constructing objects with functions as a means of dependency injection

I stumbled across some code and I was curious as to possible reasons why it would be this way.

There are two constructors, the main one being called in code and the second one being used in testing for dependency injection. The second constructor accepted a function that returns the object rather than an instance of the object itself.

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

SecondConstructor(Func<IQueryService> getQueryService){
}

I was curious as to ad开发者_运维百科vantages you would get from passing in a function instead of an instance.


There are several possible benefits for doing something like this:

  1. Decoupling: By allowing the caller to pass in a delegate rather than an instance, both the caller and the callee (in your case the class being constructed) can be decoupled from the object being passed and where it comes from.
  2. Lazy Acquisition: By passing in a delegate, the instance can be acquired in a lazy manner. In other words, the constructor could in principle cache the delegate and call it at the last possible moment, only when an instance is actually needed. If the instance is never needed, it may never get created.
  3. Recreatability: By passing in a delegate rather than an instance, the class can cache the mechanism used to create a query service on demand. In this way, the delegate acts as a factory, allowing instances of the type needed to be created on demand.


Using a Func<T> allows the product to be lazily created which is useful for optional dependencies - for example one of the classes methods may look like this:

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

If IQueryService is expensive to create this could improve efficiency if someCondition never evaluates to true.


The Func<IQueryService> is in this case really an abstract factory in disguise. So the question really is: "why would you want to use a factory instead of injecting the object itself?"

You use a factory when the lifetime of such instance matters to the consumer, you need to control the lifetime of that instance, or the instance is expensive to create. Good example of this is when objects implement IDisposable. Disposable objects often need to be controlled explicitly.

I'm personally not fond of using Func<T> delegates as factories, because it makes your code less explicit. Rather than depending on a Func<IQueryService>, let the class depend on an IQueryServiceFactory. This makes your code much more explicit. Downside of this approach is of course that you will have to write more code (not much, but still).

The second constructor uses the Dependency Injection pattern. The first constructor however, is an example of Poor Man's DI. It's a way of allowing to inject dependencies for the sake of unit testing, but saving you the need to use a dependency injection framework for your production code. A downside of this approach is the need for a dependency on the container (the Factory class in your case), a pattern which is called Service Locator. Another downside is that it makes the needed dependencies of a class less obvious.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜