October 21, 2009 IoC
October 21, 2009 IoC
At first I would like mention that I’m not first who writes such article, but I find this to be very interesting. I will start with describing of Inversion Of Control in theory starting from easy, then I will move to usage of StructureMap.
I interacted with Inversion Of Control Containers aka StructureMap when I even haven’t understanding what is it and why is it needed. I got few UT failures, saying that something is wrong with IoC setup. And I spent a lot of time figuring out what is that bootstrap class doing. So this was my first interaction. Then I decided to prepare Developers Meeting on this theme.
Inversion of Control and Dependency Injection
We will start with example which is very similar to Martin Fowler’s (http://martinfowler.com/articles/injection.html) and then will move to StructureMap using. So let us imagine that we have class MusicPlayer, which has method GetBandSongs. That method will work with SongFinder to get all songs and then will filter out songs which are created by some particular band.
As we see Music Player is coupled to SongFinder and this is not good thing. Why? At first because of extensibility issue. If SongFinder will need to use plain text file instead of XML we will need rewrite body of SongFinder, at second testability is low because we cannot pass songs into PlayBandSongs method to test it, and at third reusability is also low because logic is too generic…
Let us do some refactoring with introducing interface for SongFinder, let us call it ISongFinder.
Now we will have MusicPlayer with member of this interface type. So this allows us work with different sources of data. i.e. logic no longer depend on concrete realization.
But the Music Player is still coupled to concrete realization of finder. Current design looks like:
I do think that you want to say “Hey, put finder into player constructor!”, and you are very right here. This is one of ways how to inject dependency here. And this is pure good idea, but there are other ones which leads us to something which will give possibility to inverse controlling.
Ok, let us create factory which will create for us instances of ISongFinder. See:
And the UML:
Now we have Player decoupled from SongFinder, because creation is redirected to Factory.
Another way to have decoupled code is to introduce here Service Locator. Using Service Locator we can register couple of services and then use one of the registered somewhere we need. So we have some code which registers services we will use, let call it Assembler, and we have code where we are using particular services. Easy! See:
Let us now take a look at constructor of MusicPlayer:
And the design with ServiceLocator will look like here:
Now we got testable, reusable and extensible code. Looks very fine, but doesn’t it look difficult? Could be, because after we got decoupling of MusicPlayer and SongFinder we also got sequence dependence, our service depends on infrastructure code and we need to do cumbersome setup in tests. Actually that is correct, but system with possibility to setup Dependencies somewhere in one place is much better. That is not all. This times we have lot of IoC containers, so they allow us to configure dependency via config file or either through reflection in code during run-time!
We continue with adding to our project one of the IoC containers – StructureMap. (http://structuremap.sourceforge.net/Default.htm) With this we will no longer need our own Service Locator. So now we can setup dependencies in some Bootstrap once, but this is not static dependencies setup – we can use different implementations for different scenarios.
Let us refactor MusicPlayer with StructureMap. Registration code will look like:
And MusicPlayer constructor will be like:
So, with these two lines of code we replaced functionality of ServiceLocator. Ok let us imagine that we have Constructor dependency:
Now we can setup dependencies like here:
And get instance of MusicPlayer by ObjectFactory. And this is quite amazing thing here, because our IoC Container built dependencies tree and did all required initialization.
In real world applications we could have framework built on interfaces and we could have couple of the pluggable assemblies which goes with IoC configuration, so IoC Containers make difference between framework and library.