21

I have been reading alot about dependency injection thinking that it may be some really advanced way to program, but I can't see the difference between just avoiding global state, as when there is no global state then you are forced to pass in all dependencies to objects.

Can someone please explain to me as I think I may be missing the point about what dependency injection is?

Jon
  • 428,835
  • 81
  • 738
  • 806
yazz.com
  • 57,320
  • 66
  • 234
  • 385
  • 1
    hehe the 4th DI question I've seen. See this large answer I posted here. http://stackoverflow.com/questions/5433211/difference-between-dependency-injection-and-mocking-framework-ninject-vs-rhinomo/5433231#5433231 – gideon Mar 26 '11 at 06:55

6 Answers6

33

Dependency injection is about decoupling code.

When you avoid the use of globals by passing arguments you are decoupling code. You are removing the dependency the code has on the globals.

You can generalize this decoupling to more than just the avoidance of globals. Take the following code:

def foo(arg):
   return ClassBar(arg).attr

foo(1)

The function foo is dependent on or tightly coupled to ClassBar. The reason this is not good is you will be forced to update foo when:

  • the arguments to constructing ClassBar change
  • you want to change ClassBar to something else
  • another piece of code wants to access attr from a different object

If the code was rewritten:

def foo(instanceBar):
   return instanceBar.attr

foo(ClassBar(1))

You've pushed the coupling up to the caller. This removed the dependency from the definition of foo. This frees you from having to update foo in the cases outlined above. The more of your code that is decoupled, the fewer code changes you'll need to make.

dietbuddha
  • 8,556
  • 1
  • 30
  • 34
  • 2
    -1 for not just using the traditionally bad examples foo and bar, but using them case sensitively! :$ – Kzqai Apr 04 '11 at 07:28
  • 1
    @Tchalvak: Idiomatic Python uses capitalized words for class names and lower case word for instances and values (unless your talking about globals). In all cases like this you would use different casing as you are dealing with a class and an instance. – dietbuddha Apr 04 '11 at 16:35
  • @Tchalvak: Why are `foo` and `bar` bad examples. In this case the code is arbitrary. The only point of the example code is to show the structural changes that occur when decoupling code. I could have used `area` and `circle`, but they would have brought nothing to the example. – dietbuddha Apr 04 '11 at 16:44
  • 3
    It's just always more vague than anything else that could go there (apart from other nonsense words). For example, if you had used area and circle, or rectangle and octagon, or SomeFunction and somevar it would have instantly made clear that AnotherFunction and somevar were different concepts, or at least weren't good candidates for the same word with different cases e.g. using circle and Circle looks obviously confusing, right? Stuff like that. They're just not as good for examples as everyone using them thinks they are. – Kzqai Apr 04 '11 at 21:50
  • @Tchalvak: Fair enough. I updated `Bar` to `ClassBar` and `bar` to `instanceBar`. Perhaps that makes it clearer. – dietbuddha Apr 04 '11 at 23:16
  • 2
    Clearest, most succinct description, ever! :) – Arafangion Apr 05 '11 at 03:48
  • I know the topic is super old, but I have a question. wouldn´t a globally defined instanceBar achieve the same as the second example? why is it better to to it without globals (or just some parent class'es property?) – jacksbox Feb 14 '17 at 14:16
  • @jacksbox The difference is with DI you enforce your dependencies upon instantiation of the consuming class, or at worst during calltime. A global is sort of like an unknown dependency with no contracts / enforcements in place. It achieves the same thing - like you say - only with DI, things are defined / controlled. – lsl Mar 12 '17 at 06:40
5

What I understand about dependency injection is that you leave out the details of creating an object and only declare that such an object is needed. A framework for example will set this object later on before it's needed.

So the value here is the separation of concerns. This is useful for testing when you will inject a mockup of the real object.

Majid Alfifi
  • 568
  • 2
  • 5
  • 18
2

Dependency injection is a way for implementing the inversion of control pattern for avoiding global state for dependency resolution. You can use the inversion of control pattern with or without dependency-injection. Yes not using global variables is an important part of the equation weather you use dependency-injection or not.

Dependency injection is really nothing more than if you were to write a program in a bottom up style where the most top level portion of the application resolved dependencies for all subsystems. Say I had a program with a dependency injection configuration like:

 <bean id="world" class="com.game.World" start-method="play">
    <property name="player1" ref="player1"/>
    <property name="player2" ref="player2"/>
 </bean>

 <bean id="player1" class="com.game.LocalPlayer"/>
 <bean id="player2" class="com.game.NetworkPlayer/>

That would really be no different than if you created the objects by hand:

 public static void main() {
    World world = new World();
    world.player1 = new LocalPlayer();
    world.player2 = new NetworkPlayer();

    world.play();
 }

Using dependency injection simply means writing code like the above is handled for you. In this simple example you can't make much of a case for using it over just using code, but in larger programs it does save you a lot of time. It also prevents you or team members from taking shortcuts because it's not as wide open as when you write code.

Dependency-injection frameworks change your program from imperative style code to a declarative-style language for dependencies. So you're writing a program through this declarative language and you can augment that with lots of other features.

Features like having the framework resolve order of construction and cycle dependencies for you. Declaring external configuration and injection of values into your declared objects (i.e. property files, XML configuration, etc) which is really nice. All of these together makes dependency injection frameworks quite compelling to use over doing all of this on your own.

chubbsondubs
  • 37,646
  • 24
  • 106
  • 138
1

Another thing is that dependency injection generally creates singleton objects. In situations like services and DAOs, you would never want to have more than one object. Its also nice to have it instantiated already(generally on app startup, in spring), so you can use whenever needs arise.

mbseid
  • 1,044
  • 10
  • 18
  • 1
    Several IoC/DI frameworks allow you to choose the lifetime. You can have the container always inject the same instance (Singleton), create a new instance on each request, create an instance per thread, or (at least in Unity) inject an automatic factory delegate. – TrueWill Apr 02 '11 at 16:44
1

Assuming you are a good coder, you want to be able to test and replace your parts system easily. The best way to do this is with a modular design. That is to say you want to break down your problem into smaller problems that you can solve and keep bug free.

By using dependency injection, you are able to come up with these smaller components, test them and link them together in a standard way. This in tern results in slicker, decoupled design. In turn, your project doesn't grind begin to slow as you are never working in high complexity code (at least in theory) this productivity remains high.

If you are a skilled developer you can make use of the singleton pattern (and others) to get most of the same benefits. However, your entire team needs to have this same skill or once again you get coupled design and low throughput.

Ed_
  • 1,676
  • 2
  • 13
  • 22
0

Using dependency injection looks to be like using Windows registry. You load up the registry with things you want and then pull them out and use them in some module.

However, it breaks Object oriented code.

Say you have 20 items in your Dependency registry. A database, a logger, an exception handler and so on.

Now in a given module you have NO IDEA which of these dependency services your module uses. Your context is further lost because you don't know what will be in the dependency registry at the time you run the code!

I cannot see any benefit here. It simply makes debugging impossible.

Dave
  • 307
  • 4
  • 10
  • Depends on the flavor of dependency injection. You *always* know which service your module uses if you use explicit DI (passed as an argument into the constructor), particularly in a typed language. – thekingoftruth Aug 24 '18 at 00:55
  • one of the best descriptions of DI ive ever seen, i can tell its speaking from experience instead of regurgitating a textbook – Khlorghaal Apr 04 '22 at 23:58