Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why not pass your IoC container around?

On this AutoFac "Best Practices" page (http://code.google.com/p/autofac/wiki/BestPractices), they say:

Don't Pass the Container Around Giving components access to the container, or storing it in a public static property, or making functions like Resolve() available on a global 'IoC' class defeats the purpose of using dependency injection. Such designs have more in common with the Service Locator pattern. If components have a dependency on the container, look at how they're using the container to retrieve services, and add those services to the component's (dependency injected) constructor arguments instead.

So what would be a better way to have one component "dynamically" instantiate another? Their second paragraph doesn't cover the case where the component that "may" need to be created will depend on the state of the system. Or when component A needs to create X number of component B.

like image 348
Wil Bloodworth Avatar asked Jul 31 '09 21:07

Wil Bloodworth


2 Answers

To abstract away the instantiation of another component, you can use the Factory pattern:

public interface IComponentBFactory
{
    IComponentB CreateComponentB();
}

public class ComponentA : IComponentA
{
    private IComponentBFactory _componentBFactory;

    public ComponentA(IComponentBFactory componentBFactory)
    {
        _componentBFactory = componentBFactory;
    }

    public void Foo()
    {
        var componentB = _componentBFactory.CreateComponentB();

        ...
    }
}

Then the implementation can be registered with the IoC container.

A container is one way of assembling an object graph, but it certainly isn't the only way. It is an implementation detail. Keeping the objects free of this knowledge decouples them from infrastructure concerns. It also keeps them from having to know which version of a dependency to resolve.

like image 187
Bryan Watts Avatar answered Sep 21 '22 17:09

Bryan Watts


Autofac actually has some special functionality for exactly this scenario - the details are on the wiki here: http://code.google.com/p/autofac/wiki/DelegateFactories.

In essence, if A needs to create multiple instances of B, A can take a dependency on Func<B> and Autofac will generate an implementation that returns new Bs out of the container.

The other suggestions above are of course valid - Autofac's approach has a couple of differences:

  • It avoids the need for a large number of factory interfaces
  • B (the product of the factory) can still have dependencies injected by the container

Hope this helps!

Nick

like image 29
Nicholas Blumhardt Avatar answered Sep 22 '22 17:09

Nicholas Blumhardt