Before using Inversion of Control you should be well aware of the fact that it has its pros and cons and you should know why you use it if you do so.
Your code gets decoupled so you can easily exchange implementations of an interface with alternative implementations
It is a strong motivator for coding against interfaces instead of implementations
It’s very easy to write unit tests for your code because it depends on nothing else than the objects it accepts in its constructor/setters and you can easily initialize them with the right objects in isolation.
IoC not only inverts the control flow in your program, it also clouds it considerably. This means you can no longer just read your code and jump from one place to another because the connections that would normally be in your code are not in the code anymore. Instead it is in XML configuration files or annotations and in the code of your IoC container that interprets these metadata.
There arises a new class of bugs where you get your XML config or your annotations wrong and you can spend a lot of time finding out why your IoC container injects a null reference into one of your objects under certain conditions.
Personally I see the strong points of IoC and I really like them but I tend to avoid IoC whenever possible because it turns your software into a collection of classes that no longer constitute a “real” program but just something that needs to be put together by XML configuration or annotation metadata and would fall (and falls) apart without it.
If you follow these simple two steps, you have done inversion of control:
Separate what-to-do part from when-to-do part.
Ensure that when part knows as little as possible about what part; and vice versa.
There are several techniques possible for each of these steps based on the technology/language you are using for your implementation.
The inversion part of the Inversion of Control (IoC) is the confusing thing; because inversion is the relative term. The best way to understand IoC is to forget about that word!
Event Handling. Event Handlers (what-to-do part) — Raising Events (when-to-do part)
Interfaces. Component client (when-to-do part) — Component Interface implementation (what-to-do part)
xUnit fixure. Setup and TearDown (what-to-do part) — xUnit frameworks calls to Setup at the beginning and TearDown at the end (when-to-do part)
Template method design pattern. template method when-to-do part — primitive subclass implementation what-to-do part
DLL container methods in COM. DllMain, DllCanUnload, etc (what-to-do part) — COM/OS (when-to-do part)