Why is dependency injection better than using factories?

I read about dependency injection, and I understand the appeal of defining dependencies in XML, as it does in many frameworks. I am working on a large system where we usually call factories to get specific objects, and I try to understand why dependencies were manually entered, as shown in this Wikipedia article is supposedly better.

It seems to me that calling factory is better because:

  • The calling code does not need to know or care that a certain dependency exists.
  • The calling code does not need to be changed if new dependencies are added to the interlocutor.
  • The call code should not contain any logic designed to select a specific instance for input.

It seems to me that dependency injection offers only benefits when the calling code needs to decide on a specific class for the dependency. Almost like "Here is my data, now process it."

Is there something I missed?

Update: To clarify, our existing code basically calls factory directly. So, to get a new Ball object, you will see the following code:

Ball myBall = BallFactory.getObject(); 

Many of these plants are implemented to allow registration of new types of specific objects - the plugin framework.

So, after looking at some of the initial comments, it looks like with DI my calling code is usually not passed in the Ball object, but instead BallFactory. I assume the advantage of this is that the class can be more general, since it is not even related to the factory that it uses.

+4
source share
4 answers

Nothing is better than the other; you can use dependency injection on their own, plants on their own, or a combination of them.

Also, all three references to factories are equally valid for dependency injection. Remember that a dependency can be entered at any given time, not necessarily with an immediate “call code”. In fact, this is what the DI framework does for you - it is basically a giant factory that creates your main application object and inserts all the dependencies for you.

Explicit use of factories is only useful when your code should be able to create new instances of dependencies at runtime. Otherwise, it is much simpler to simply use the DI structure to enter all the static dependencies during application startup.

+2
source

Injection injection helps with unit testing. It allows you to separate and isolate the functionality of your class, because any of its dependencies can be introduced (and therefore also mocked) into the class. This is especially useful if dependencies access external resources, such as databases.

I recently read an article that demonstrated the benefits of dependency injection in testing. In particular, we are talking about static methods, but the same could be applied to factories.

http://misko.hevery.com/2008/12/15/static-methods-are-death-to-testability/

Like @deceze, though if you enter your factories you get the best of both worlds ...

+3
source

It is often useful to use dependency injection and abstract factory in combination - but for two different reasons. The reason for using (manual) dependency injection is that it allows you to enter a special object during unit testing. If your design indicates that the calling code is not responsible for creating the object (starting with 1-2-3 bullets), then the dependency indicated by it should be an instance of an abstract factory . The object to be entered will use the factory to create objects whenever necessary.

Suppose you use two factories to create dependencies (there is only one dependency, Dice) for light and complex backgammon games:

 public class EasyGameFactory implements GameFactory { Dice createDice() { return new LuckyDice(); } } public class NormalGameFactory implements GameFactory { Dice createDice() { return new RandomDice(); } } 

For the purposes of unit testing, you would prefer to use none of the Dice implementations, so you are writing a special GameFactory implementation:

 public class CustomGameFactory implements GameFactory { private Dice mDice; public CustomGameFactory(Dice dice) { mDice = dice; } Dice createDice() { return mDice; } } 

This factory should not be part of your production code. You supply the factory with a special implementation of Dice through test code:

 public class TestBackgammon { @Test public void shouldReturnDiceThrown() { SettableDice dice = new SettableDice(); Game game = new GameImpl(new CustomGameFactory(dice)); dice.setDice(new int[] {4, 5}); game.nextTurn(); assertArrayEquals(new int[] {4, 5}, game.diceThrown()); } } 
+2
source

Using dependency injection or not is a bit like the difference in C between using printf and using fprintf . Caller gains flexibility through choice. When the caller does not want flexibility (for example, if all the output from your program goes to stdout, never stderr or a file), flexibility is a sheer burden since the caller must always pass the same “correct” value.

If you see dependency injection as a net workload, it means that your callers are not actually using it.

Your points 1 and 3 say that "the calling code has less freedom to influence what happens," which is not always an advantage. The test code, in particular, benefits from dependency on injections, but there may also be situations where subscribers want flexibility for other reasons. Are you logging in with printf , or are you logging in by calling functions on a nested log?

Point 2 boils down to how you develop your APIs. Yes, if the original design needs to be changed, then using fixed hidden dependencies you can protect the API from reflecting this change. Sometimes you can maintain the old API with the default value of a new dependency and add a new method / constructor with an additional parameter somewhere.

All that is said, the standard libraries in the languages ​​that I used do not require a huge number of dependency injections. Thus, you are not alone in thinking that your APIs are not needed, but I suspect that you can get more from this internally than you are now. For example, can you verify your network code without connecting to a remote computer? If not, consider whether this part of your test procedure will be simpler, faster, and give a more accurate diagnosis if you could.

+1
source

All Articles