.NET tanker & tips

.Net, jQuery og andre nørdede emner

Dependency Injection Principle and the Geekmobile

marts 17
by steffen 17. marts 2017 06:28

Almost everyone in the development environment agrees that Dependency Injection (DI) is a corner stone of good software design. When implemented correctly it gives quite a few advantages to the code. The biggest advantages are that the code becomes easier to unit test and that the code will be more loosely coupled. However the concept of Dependency Injection can be a little hard to grasp at first. I will therefore try to first in explain in it general terms and afterwards provide some code examples.

There are two rules to the Dependency Injection Principle:

  • High-level modules should not depend on low-level modules. Both should depend on abstractions
  • Abstractions should not depend on details. Details should depend on abstractions

Let's take a look at what that means. The first rule means that each class should have as few references (none, if possible) to concrete classes as possible. Not to say that a class can't use a concrete class, but it is a clear code smell if there is. Instead you should use abstractions ie. interfaces or abstract classes where possible. The use of interfaces makes the code loose coupled, hence making it much more flexible and handling changing requirements much easier.

The basic idea that, in order to prepare your code for future changes, it should be structured in a way that will make changes easy, without causing a tsunami of changes other places in your code. This is commonly referred to as loose coupling.

The second rule, means that you have to design your code, so that if you change something in your concrete class, it must not change the outcome from what the abstraction expects.

This is best illustrated with an example (inspired by Vincent Ramdhanie's answer on SO). When I get into my car, all the controls (eg. pedals and steering wheel) are abstractions (or interfaces if you will) between me and the mechanics of the car. I understand the abstractions and by using the controls I can control the car: when I press the right pedal the car will accelerate and when I press the middle pedal (or left if you're not driving a stick), the car will decelerate.

Steering wheel from the geek-mobile

Steering wheel from the Geekmobile (image from xboxfreedom.com)

If we change some of the implementation details (eg. changing the engine in the car), you cannot change the abstractions. For instance you cannot swap the pedals, so that the brake pedal is now on the right. The same rules should apply to you code. If you have a calculator class, which implements an interface with a method called Add, you can change the code in the concrete implementation, but never in a way that it changes the abstraction (eg. dividing instead of adding). This is of course a very simple example and you might think your code is much more complex. That might be true, but this is one more reason for you to try to design your code to be as simple and loosely coupled as possible. If you design your classes with the Single Responsibility Principle in mind, your interfaces should become more simple and it should be easier to determine if a change in the details effects the abstraction.

To sum up the Dependency Injection Principle is a way to design you classes, so that the have loose coupling and being aware that do not change the abstractions (the implied understanding of what a interface promise to do) of the system. The next blog post will be much more code heavy and will describe how to use Dependency Injection to put the Dependency Injection Principle into use.

Tags:

Dependency Injection | General

blog comments powered by Disqus