Make sure to read a follow-up version of this article.
This tutorial assumes you know what DI/IoC is but you are still unsure how to use it in complex scenarios.
Let me start with a common issue. Somewhere deep in your solution, in an assembly, there is a business service:
public interface IBusinessSerivce
{
void DoSomeWork();
}
Then, possibly in yet another assembly you have a class which uses the service:
public class SomeAnotherClass
{
public void DoThat()
{
IBusinessSerivce service = ???
}
}
How are you supposed to satisfy the dependency here?
There are at least few possible approaches here. Assuming you don’t want a concrete class to be instantiated here, you are left with three possibilities. Let us discuss them one by one.
First possibility – would be to use a service locator. A service locator acts just like a powerful magician – it can show up anywhere in your code and create any service you want (assuming it was registered in the IoC container):
public class SomeAnotherClass
{
public void DoThat()
{
IBusinessSerivce service =
ServiceLocator.Current.GetInstance<IBusinessSerivce>();
}
}
Yep, a kind of magic indeed. No additional dependencies, clean code.
But … is it really? Well, there is one additional dependency! To be able to use the locator, you had to make your project dependant on the locator implementation!
Is this wrong? Possibly. The class library is no longer self-contained. If you distribute it in a binary form, you have to include all the stuff which comes with the locator, one (or more) additional libraries.
Yet another reason a locator is bad is that although the dependency exists (SomeAnotherClass depends on IBusinessService), it is so implicit, so intimate, that any client of SomeAnotherClass would not be aware of the dependency. It’s just, “ok, let me use the class and … boom! I got an exception in runtime because the locator was not able to resolve the service and this was because the implementation had not been registered in the container but how the hell I was supposed to know that the class requires the service implementation to be registered? By studying the implementation?”
This is why the Service Locator is currently considered an anti-pattern.
Another possibility – but let just introduce it for the sake of completeness – would be to actually introduce an explicit dependency to … the container:
public class SomeAnotherClass
{
private IUnityContainer container { get; set; }
public SomeAnotherClass( IUnityContainer container )
{
this.container = container;
}
public void DoThat()
{
IBusinessSerivce service =
container.Resolve<IBusinessSerivce>();
}
}
Well, at least one problem goes away – this time the dependency is explicit and the client of SomeAnotherClass must satisfy it in an explicit way. The other problem remains however, the dependency to the IoC container infrastructure. It just doesn’t look good. Surprisingly, I sometimes see people coding like this.
An ultimate possibility – because SomeAnotherClass depends on the service, let’s make this dependency explicit:
public class SomeAnotherClass
{
private IBusinessSerivce service { get; set; }
public SomeAnotherClass( IBusinessSerivce service )
{
this.service = service;
}
public void DoThat()
{
IBusinessSerivce service = this.service;
}
}
Great, the dependency is explicit and the other dependency – to the IoC infrastructure is gone. And although this approach can possibly lead to other issues (namely the “constructor over-injection antipattern”) these can possibly be resolved somehow or somehow else.
Problem solved.
Is it, really?
Unfortunately, no. This is where the problem starts! By making the dependency explicit, we just throw the issue away. But it just hits someone else, directly in the face. Because now the client of SomeAnotherClass has exactly the same problem!
public class SomeClass
{
public void DoThis()
{
SomeAnotherClass another = new SomeAnotherClass( ??? );
another.DoThat();
}
}
Well, to satisfy the dependency between SomeAnotherClass and IBusinessService I need an instance of the latter. And how do I resolve it?
Well, there are three possibilities, we’ve just discussed them :) And we concluded that the best we could do is to make the dependency explicit:
public class SomeClass
{
private IBusinessSerivce service { get; set; }
public SomeClass( IBusinessSerivce service )
{
this.service = service;
}
public void DoThis()
{
SomeAnotherClass another = new SomeAnotherClass( this.service );
another.DoThat();
}
}
This doesn’t look good, unfortunately and this is the core of the problem. By having multiple services in your system and multiple dependencies between various classes, this approach would end up in an object graph where each class depends on all possible services because possibly one of its dependant classes (or the class two, three or more nodes away in the dependency graph) depends on it!
Can you see it? You just can’t rethrow the responsibility to satisfy class dependencies to the client of the class because the client has its clients and they have their clients, too. The sole point of writing this entry is to show how to stop this madness of endless explicit dependencies which would flood your system.
But let us recap facts.
1. SomeAnotherClass really depends on the service because it makes use of it (DoThat method).
2. SomeClass doesn’t really depend on the service, it just depends on SomeAnotherClass. And to resolve the dependency, the SomeClass must somehow create an instance of the service.
3. Most probably we still want the IoC container to register/resolve the concrete implementation of the service but in the same time we don’t want SomeClass to depend on the service locator and/or the container in an explicit way.
And to cope with the issue we are going to introduce a factory. The factory will let its clients to create instances of the service. But we don’t want a concrete factory as it would end up with one, specific way of providing instances. Instead, we want the factory to be parametrized. We want a concrete implementation of the factory to be provided for the system.
For this to work, we will need a conrete class, a factory provider, which will be responsible for registering and providing a concrete implementation of the factory.
public interface IBusinessServiceFactory
{
IBusinessSerivce CreateService();
}
public class BusinessServiceFactoryProvider
{
public static IBusinessServiceFactory Factory { get; private set; }
/// <summary>
/// To be called in the Composition Root
/// </summary>
public static void SetupFactory( IBusinessServiceFactory factory )
{
Factory = factory;
}
}
Now I can go back to my SomeClass, the one which has to satisfy the dependency to the service but is not itself dependant on the service:
public class SomeClass
{
public SomeClass()
{
}
public void DoThis()
{
var factory = BusinessServiceFactoryProvider.Factory;
SomeAnotherClass another = new SomeAnotherClass( factory.CreateService() );
another.DoThat();
}
}
(#side note for purists who do not like static properties: the factory provider can be implemented to hide the lifetime of the factory:
public class BusinessServiceFactoryProvider
{
private static IBusinessServiceFactory _factory { get; private set; }
public IBusinessServiceFactory Factory
{
get
{
return _factory;
}
}
/// <summary>
/// To be called in the Composition Root
/// </summary>
/// <param name="factory"></param>
public static void SetupFactory( IBusinessServiceFactory factory )
{
_factory = factory;
}
}
so that the client code now becomes
public class SomeClass
{
public SomeClass()
{
}
public void DoThis()
{
var factoryProvider = new BusinessServiceFactoryProvider();
var factory = factoryProvider.Factory;
SomeAnotherClass another = new SomeAnotherClass( factory.CreateService() );
another.DoThat();
}
}
or even
public class BusinessServiceFactoryProvider
{
private static IBusinessServiceFactory _factory { get; private set; }
public IBusinessServiceFactory Factory
{
get
{
return _factory;
}
}
/// <summary>
/// To be called in the Composition Root
/// </summary>
/// <param name="factory"></param>
public static void SetupFactory(
Func<IBusinessServiceFactory> factoryCreationMethod )
{
_factory = factoryCreationMethod();
}
}
which makes it possible to implement arbitrary lifetime policy of the factory
#end of side note)
The factory provider really solves the issue once for all. I can provide a concrete implementation of the factory by making the configuration of the factory provider a part of the Composition Root:
class Program
{
static void Main( string[] args )
{
ConfigureContainer();
SomeClass sc = new SomeClass();
sc.DoThis();
Console.ReadLine();
}
static void ConfigureContainer()
{
IUnityContainer container = new UnityContainer();
// register the service implementation
container.RegisterType<IBusinessSerivce, BusinessServiceImpl>();
// configure the factory provider
BusinessServiceFactoryProvider.SetupFactory(
() =>
new ContainerBusinessServiceFactory( container ) );
}
}
class ContainerBusinessServiceFactory : IBusinessServiceFactory
{
#region IBusinessServiceFactory Members
private IUnityContainer container { get; set; }
public ContainerBusinessServiceFactory( IUnityContainer container )
{
this.container = container;
}
public IBusinessSerivce CreateService()
{
return container.Resolve<IBusinessSerivce>();
}
#endregion
}
Note that the ContainerBusinessServiceFactory is just a concrete implementation of the service factory and although it strongly depends on the container infrastructure, it does not really matter as the class is now a part of the Composition Root – it is defined close to the Main method which plays the role of the CR. In the same time the concrete implementation of the service factory class is not really important to its clients as they access the factory by using the provider. The key features of such approach are:
1. All the clients of the service do not depend on the container infrastructure, instead they depend on the factory provider
2. A concrete implementation of the factory can (and possibly should) depend on the container but since it is a part of the composition root, it frees other classes from being dependant on the container infrastructure
3. The intention of the factory provider is now clean and it is safe to make it a required part of the CR. I could even provide a default implementation of the factory which by convention uses the container to resolve service (because most probably this is what I’d really want to do) so that no configuration of the factory provider is necessary at all in the Composition Root. This would introduce a possible issue however – because now a default service provider would depend on the container infrastructure (so that we are back in the situation where the service library has to be distributed together with container libraries).
4. I can freely change the implementation of the factory provider so that the code uses another, more sophisticated conrete factory but this does not influence any client code at all
Happy coding.
6 comments:
With the code samples in front of me I can finally follow your arguments from our chat on SO. I think the problem lies in how you model your dependencies. SomeAnotherClass depends on IBusinessService. But SomeClass does not. It depends on SomeAnotherClass. So I would inject SomeAnotherClass into SomeClass instead of passing around IBusinessService and new'ing up instances of SomeAnotherClass.
Refering to your statemement "It just hits someone else". Well, yes. That's what Dependency Inversion is all about. You don't expect your components to figure this kind of problems out on their own. You let more informed components (i.e. the Composition Root) make the decision what implementation they should use. The components just say "I need X". And then "someone" (DI container, object builder etc.) gives them what they need.
@Sebastien: my intention during the discussion was that although this sounds well on the paper, in practice you can't always rethrow the responsibility of creating instances of services to the caler. And in such cases, the presented solution seems to be the only acceptable one.
Dear Wiktor,
first of all I've found your article quite useful, and thank you for it. However, I have one thing I cannot figure out.
I'm working on a complex WinForms project with lots of forms, services and repositories. As I read your code, it looks like you suggest that I should create a factory for EACH of my service classes what I would like to inject as a dependency at any point of the whole code. If it' s true, this means a whole lot of factories, basically all doing the same. So why not make a generic factory interface, whose "comtainer" implementation would use the generic Get<> method of for example the Ninject IKernel (I guess Unity has something like that as well). Let's assume I create this generic factory interface... now it looks like I got back to a service locator, doesn't it?
Just for further clarification, with the "factory" solution I still see an implicit dependency in your code, where you call the factory at that constructor. I don't quite understand why it is better than a service locator at the same place.
Could you tell me what's the difference (in theorical and practical way as well) between a generic factory interface, and a service locator?
I hope you understand my problem and question.
Regards,
Zoltán
@Zoltan, thanks for these comments. You touched the exact nature of the issue. My opinion is as follows: there is probably nothing wrong with a generic factory. However, there is still a HUGE difference between a factory like this and a locator.
You see, a locator implementation "breaks the barier", it introduces another unwanted hard dependency between your infrastructure and the implementation of the locator. Imagine that you distribute your library and you have to provide it TOGETHER with Unity or Ninject just because internally you rely on the concrete locator.
On the other hand, a factory or a set of factories are still independent. I could reference your library and provide MY OWN, concrete provider and inject it into your library.
In an ideal world, which this approach tries to aim, the only project that references actual implmementation of the IoC container is the Composite Root project - a main executable or a website project. Any other projects in the solution remain "agnostic", unaware that somewhere there exists something like IoC which will implement providers for factories.
In this ideal world it is even possible to use the same library in a project that DOESN'T use an ioc container at all - just by providing specific implementation of factory providers.
I hope this makes sense and supports my reasoning.
Regards,
Wiktor
Can we possibly move this discussion to email? You can find me easily at wzychla[(atgoeshere)]gmail[dot]com.
Post a Comment