The dependency inversion is a principle; it has nothing to do with technologies. This principle says that depending on abstractions is better than depending on concrete implementations. However it’s common among developers learning about design patterns increasing the complexity in the name of this principle or any of its related patterns. The dependency inversion principle can be achieved with the strategy pattern or the inversion of control practice.

Use the strategy pattern when you need many different operations/algorithms on the same object structure/context. Usually each operation is encapsulated within a class. Behaviour changes are initiated and controlled by the client, which means the client knows the different operations as described in the following sample:

Employee employee = new Employee(123, "George", "123 Baker St.");
employee.Schedule = new MonthlySchedule(); //Injection by using a setter/property

The Inversion of Control –IoC– practice is implemented with the Dependency Injection pattern or the Service Locator pattern; both patterns do the same that the strategy except by the fact that the injection is at runtime via constructor or setter. There are many ways to inject an implementation by runtime depending on the selected technology. You can do it by using reflection directly or by using other framework built on top of it, like Unity. In many scenarios the strategy pattern it’s enough and the IoC is over-engineering.

I’d say the IoC practice makes sense in a plug-in architecture (i.e. a game maker platform) or in any situation which needs different and complex business rules being replaced at runtime through configuration. Having that said a cross-cutting logging class doesn’t count.

Some notes:

  • When packaging your strategy or IoC implementation make sure your Interfaces and/or abstractions are shared as cross cutting concerns.
  • Just because you can invert dependencies doesn’t mean you should.
  • If the object initialization requires more than one line of code then don’t repeat yourself and use the Factory method pattern.
  • Every time you win in an aspect you will be sacrificing another one, so try to minimize collateral effects like sequential coupling (which it means that a client must call some methods in a given order before using the required one)
  • Strategy and State are very similar but the State pattern should be used when having some well-defined state transitions, each of them encapsulated in classes. The structure/context maintains its own state and it has many strategies.
  • Strategy and Visitor are very similar but in the visitor you have many structures/contexts and many operations/algorithms. Operations are outside the object, so it does not have Context, structures are passed to implementations.

Cheers,

Javier Andrés Cáceres Alvis

Microsoft Most Valuable Professional – MVP
Intel Black Belt Software Developer