Dependency Injection: a beginners introduction

Dependency Injection Armored Knight

Let’s explain dependency injection (one of the most used design patterns) with a very good example found in the book «Spring in Action, 4th Edition».

The problem with coupling code

Consider the Kingth class shown next.

As you can see, DamselRescuingKnight creates its own quest, a RescueDamselQuest, in the constructor. This makes a DamselRescuingKnight tightly coupled to a RescueDamselQuest and severely limits the knight’s quest-embarking repertoire. If a damsel needs rescuing, this knight’s there. But if a dragon needs slaying or a round table needs… well… rounding, then this knight’s going to have to sit it out.

What’s more, it’d be terribly difficult to write a unit test for DamselRescuingKnight. In such a test, you’d like to be able to assert that the quest’s embark() method is called when the knight’s embarkOnQuest() method is called. But there’s no clear way to accomplish that here. Unfortunately, DamselRescuingKnight will remain untested.

Coupling is a two-headed beast. On the one hand, tightly coupled code is difficult to test, difficult to reuse, and difficult to understand, and it typically exhibits «whack-a-mole» bug behavior (fixing one bug results in the creation of one or more new bugs). On the other hand, a certain amount of coupling is necessary – completely uncoupled code doesn’t do anything. In order to do anything useful, classes need to know about each other somehow. Coupling is necessary but should be carefully managed.

Fixing coupling code with dependency injection

With Dependency Injection, objects are given their dependencies at creation time by some third party that coordinates each object in the system. Objects aren’t expected to create or obtain their dependencies.

To illustrate this point, let’s look at BraveKnight in the next listing: a knight who’w not only brave, but also capable of embarking on any kind of quest that comes along.

As you can see, BraveKnight, unlike DamselRescuingKnight, doesn’t create his own quest. Instead, he’s given a quest at construction time as a constructor argument. This is a type of Dependency Injection known as constructor injection.

What’s more, the quest he’s given is typed as Quest, an interface that all quests implement. So BraveKnight could embark on a RescueDamselQuest, a SlayDragonQuest, a MakeRoundTableRounderQuest, or any other Quest implementation he’s given.

The point is that BraveKnight isn’t coupled to any specific implementation of Quest. It doesn’t matter to him what kind of quest he’s asked to embark on, as long as it implements the Quest interface. That’s the key benefit of Dependency Injection -loose coupling. If an object only knows about its dependencies by their interface (not by their implementation or how they’re instantiated), then the dependency can be swapped out with a different implementation without the depending object knowing the difference.

One of the most common ways a dependency is swapped out is with a mock implementation during testing. You were unable to adequately test DamselRescuingKnight due to tight coupling, but you can easily test BraveKnight by giving it a mock implementations of Quest.

More info at Wikipedia!

Deja una respuesta