1

I am thinking about using of DI and Unity in my project. And I have a question: how it will reduce coupling? From my point of view, it is increasing of coupling, because:

  1. I need to create UnityContainer and register all types there. It means that I need to have the reference to all assemblies in assembly where this container is created.

    IUnityContainer UnityContainer;
    //....
    IUnityContainer UnityContainer= new UnityContainer();
    UnityContainer.RegisterType<IMyService, CustomerService>();
    
  2. I need to create an instance of my service using Resolve but it means that I need to have the reference to assembly with container.

    var service = SomeClassWithContainer.UnityContainer.Resolve<IMyService>();
    

Have I misunderstood something or in reality it is increasing of coupling?

Oleg Dudnyk
  • 1,009
  • 1
  • 10
  • 22
  • Your question seems about Unity rather than IOC containers in general - perhaps you would like to update your title to reflect that? – Jon Skeet Aug 27 '11 at 20:06
  • @Joen Skeet: Do other IOC containers behave different? If so could you specify an example with some container which does not create this heavy coupling? – Oleg Dudnyk Aug 27 '11 at 20:15
  • Guice and Spring (both in Java) certainly don't. I wouldn't be at all surprised to find some of the other - many - .NET containers don't. It's quite possibly that Unity can work without this too. – Jon Skeet Aug 27 '11 at 20:18
  • 1
    You may find this answer helpful: http://stackoverflow.com/questions/5667801/arguments-against-inversion-of-control-containers/5668093#5668093 – Mark Seemann Aug 27 '11 at 21:39
  • 1
    @Mark Seeman: thank you for the link, but Nat Pryce persuaded me more not to use IOC containers: http://www.natpryce.com/articles/000783.html – Oleg Dudnyk Aug 28 '11 at 05:07
  • 1
    You should be aware that Nat Pryce speaks from experience mostly with Java containers, which tend to enforce a much higher degree of coupling to the container than the typical .NET container. – Mark Seemann Aug 28 '11 at 08:11

2 Answers2

9

I think you misunderstood how your dependencies should be resolved.

1.) A reference to Unity should only be needed in your bootstrapping code which is at a single central spot in your application.

2.) Once bootstrapping is done all dependencies (ideally) are resolved using constructor injection which is automatically done by Unity if the containing class is resolved via Unity - it is trickling down the object graph. The example you use is really just the "service locator" pattern and not DI.

This does reduce coupling since instead of directly creating a concrete class your class depends on, you "inject" dependencies (again ideally some abstraction like an interface) into your class which allows you to substitute those dependencies with other classes i.e. in the unit testing scenario.

BrokenGlass
  • 158,293
  • 28
  • 286
  • 335
  • Sorry, but it does not give me much information without some good example. It seems that references are still needed. – Oleg Dudnyk Aug 27 '11 at 20:25
  • @gorik: There's a pretty good example using Unity as IOC at http://www.mattlong.com.au/?p=142 which details bootstrapping and decoupling using constructor injection – BrokenGlass Aug 27 '11 at 20:49
  • 3
    That's correct: The bootstrapping assembly (compostion root) needs to reference all other assemblies to be able to do the wiring. By having this part of the application take a dependency on all other assemblies, you can reduce the amount of coupling that all other parts of the application have on each other, which far outweighs the costs of having that complexity in that single spot. – Steven Aug 27 '11 at 20:50
6

Your question contains an example of the Service Locator anti-pattern:

public class UsesMyService
{
    private readonly IMyService _service;

    public UsesMyService()
    {
        _service = SomeClassWithContainer.UnityContainer.Resolve<IMyService>();
    }
}

This is fundamentally different than the Dependency Injection pattern because of the direction the information flows: in the above example, you reach out and ask for the service, whereas in the example below, you are handed the service:

public class UsesMyService
{
    private readonly IMyService _service;

    public UsesMyService(IMyService service)
    {
        _service = service;
    }
}

This pattern, known as constructor injection, decouples the UsesMyService class from details about the surrounding infrastructure. Now, anyone with an implementation of IMyService can create instances of UsesMyService without having to know to configure a central static location.

How would they even know what to configure? They would either need the source code or some documentation telling them that the class depends on IMyService. The constructor parameter cleanly expresses that requirement to consumers without any external reference.

If you follow this pattern throughout your libraries, you bubble the responsibility of assembling the objects all the way to the outermost layer, known as the Composition Root. This single location, usually the top-level application class, is the only place with references to all of the libraries you are using. That is where the container lives, and no other class in your entire solution needs to reference it.

Bryan Watts
  • 44,911
  • 16
  • 83
  • 88