8

I've a decent amount of OOP with various languages but am pretty new to Java.

I'm reading through a lot of tutorials where large numbers of objects are created within the code of a class, and I'm trying to run through them but build versions of the classes in the tutorials that do Dependency Injection instead of instantiating all the classes themselves.

But Java is not like other languages I've used in that pretty much everything is an object. If I was to literally inject everything then the result would be very messy and hard to follow.

Obviously you wouldn't inject String objects, and I'm guessing there are other objects you wouldn't inject, but I'm not sure where the line should go. At what point does DI stop being the right thing to do, and when does it start being a burden? How do you decide pragmatically what to inject and what to just instantiate?

FYI, the tutorials I'm doing are http://edn.embarcadero.com/article/31995 and http://docs.oracle.com/javase/tutorial/networking/sockets/clientServer.html for building a simple client and server. I'm not copying them line for line though, I'm trying to create equivalent classes that follow best practice

1

5 Answers 5

4

In .Net (which is similar in this regard that everything is an object), I use DI mostly with my domain objects (entities, repositories and services) and application objects (controllers, view models), so repos/services get injected into controller/view models and similar. This means my business and application logic is fully testable, which is the primary reason I use DI.

Basically the objects that you inject and inject stuff into, are mostly objects that are specific to the solution you are building. If some object is "native" to the language or framework (like .Net), there's probably no need to inject it. A lot of objects need string to represent data, and a string is basically a "language feature" that is not specific to your domain. The same thing applies to enumerables, lists, arrays and a whole lot of other stuff that does not need to change when you want to run your class in isolation from the rest of the system.

The most important thing to look at is coupling between your domain/application classes. If an object does not introduce tight coupling, then it's usually safe to just create it. One of the ways to check for coupling is to try to run the methods in a class in isolation (which is basically unit testing). What needs to be DI-ed are all dependencies that you need to mock out, in order to make sure that the class you're testing is really running in isolation from the system.

1
  • Another way to look at it is what is it that your class or your method is trying to do? The classic example is that you want to save an object. The logic in that class/method should be about saving the object, not going off and doing boiler plate work of creating connections etc, that sort of service/resource could/should be DI'd in. Commented Mar 11, 2013 at 12:27
4

Firstly, it's OK to use the new keyword, really! DI is a fantastic technique, but there is a temptation to overuse it. Times where you might want to use DI are:

  • Test Doubles - Often with unit tests you want to mock out / test double a 3rd party resource as you don't want to bring that 3rd party resource up (e.g. A full Oracle DB). For example, instead of a creating a new database connection to the big Oracle DB, you might want to replace that connection with one to an HSQL (in memory database) instead.

  • When you want to control the scope (~lifespan) of that object and the natural Java object lifecycle doesn't work for you. Many Java based DI frameworks allow you to do this.

  • When you want singletons.

  • Anytime you think you need a Factory, Service Locator or similar. This includes if you need different factories (rare, but it happens).

At other times, simply create a new object, in fact if in doubt, create a new object - you can always DI it when you see the need later :-).

4
  • Your first point COULD mean absolutely anything, so I'm not sure how you've answered the question. And I've seen many places where using DI to inject a Factory, rather than trying to build a Factory via DI, is by far the better solution, so I'm dubious about the last point too.
    – pdr
    Commented Mar 11, 2013 at 9:33
  • Edited to make the points a little clearer Commented Mar 11, 2013 at 10:48
  • I've never heard the phrase Test Doubles, I thought you meant test actual docs.oracle.com/javase/6/docs/api/java/lang/Double.html. Commented Mar 11, 2013 at 11:19
  • 1
    @NimChimpsky a test double is a generic term for any mock, stub or other stand-in. xunitpatterns.com/Test%20Double.html
    – user4051
    Commented Mar 11, 2013 at 11:31
1

In general, I find a class should only ever be new'd from one other class.

This is because once you go down the road of dependency injection, every object that's using new has to inject all the dependencies of the objects it creates, which means the parent object has to know all those dependencies too. If A has a dependency on B and C creates A instances with new then C automatically needs to have a dependency on B, even if C never uses B directly. First that violates separation of concerns, unless C's only job is to create As. Otherwise it creates a problem if you ever want to add a dependency to A because all things that create it now need to add that same dependency. They really shouldn't be concerned with that. It's better to have C declare a dependency on AFactory and AFactory have a dependency on B. Then you can add dependencies to A all you want, and only AFactory has to change.

0

From Wikipedia:

The primary purpose of the dependency injection pattern is to allow selection among multiple implementations of a given dependency interface at runtime, or via configuration files, instead of at compile time. The pattern is particularly useful for providing stub test implementations of complex components when testing, but is often used for locating plugin components, or locating and initializing

You should not need to inject strings, you can simply pass them as parameters to the relevant method. You should not need to inject any data, appart from config.

Good unit tests help you localise errors and therefore you should test your code independently from other units of code. DI can help you achieve this.

-1

"At what point does DI stop being the right thing to do, and when does it start being a burden?..."

First of all i like DI and uses it a lot so don't get me wrong

DI is great for server side but the games changes all together when it comes to Gui programming. For e.g. I incorporated Guice to an existing GUI app developed in Swing

  • You need to refactor alot to get rid of stuff like static factories, nested dependencies, etc.
  • You need to be aware of how DI container create/handle objects for e.g. if it create objects eagerly on start up then you can have a performance issues(can be any app but particularly in GUI apps 15-40 sec delay matters alot). You may tweek the setting providing DI container allows for it.
  • TO incoprporate DI into an existing project you need revolution than evolution

How to handle nested dependecies?

let say you need to access some dependencies in deeply nested classess , you can use DI in one of the following way:

  • Modify constructor to have constructor injection (So know we end of with constructor taking lot of params...)?
  • Use field injection (Which is not good solution because we are exposing our fields)
  • Use setter injection(So know we need to create unnecessary setters in our code)

How about if you want to create object using new()(because the object need to be created at Runtime depending on some criteris) and want to register it into the container(Guice doesn't handles objects created with new(), which is good) ? So now you need to turn your focus back to container rather than developing new functioanlities in your app.

Final words in some cases using DesignPatterns + creative thinking and good architecture design, you can avoid situtations where gaine is small and hassles are hig as a result of introducing DI

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.