1

I am new to Java or programing in general, and I normally would have an instance of the Main class as a static method to access it easily from other classes. For example. private static Main instance; then I'd make a getter for it public static Main getInstance() and on other classes I would simply do Main.getInstance().otherMethods(); to get other methods and variables that were declared on the Main class.

I was recently told that this is not recommended and was told that I should use Dependency Injection instead. My question is why should I not use this in Java and why would Dependency Injection be better? What is the difference between using this way or simply passing it as an method parameter and what are the advantages and disadvantages of it?

Alex Shesterov
  • 26,085
  • 12
  • 82
  • 103
  • https://github.com/google/guice/wiki/Motivation – JB Nizet Sep 14 '18 at 13:17
  • 1
    Looks like you're using a singleton pattern (or at least something that ressembles it ; I hope your classes' constructors are private!), so I suggest just searching for 'singleton vs DI' and you'll find a lot of articles on the topic. – Aaron Sep 14 '18 at 13:19
  • You might want to read [a book](https://manning.com/seemann). – Steven Sep 15 '18 at 09:31

2 Answers2

1

There are tons of questions and answers about this already. You can search for "why DI" to get a lot of theory on the reasons. For example: Why does one use dependency injection?

The key advantages of DI are:

  • Flexibility — if you ever need to replace a component, or use multiple components instead of a single one, then DI lets you adjust your code with a few changes only.

  • Easier to Unit-test — you can inject a mock-implementation of a dependency-component into the component being tested, and test only the target component.

A real life example:

I've once seen a project which used a Singleton database access class. There was a single global constant in the whole application:

public static final DB_INSTANCE = ...;

which was used all around the application, like this:

DB_INSTANCE.runQuery("SELECT ...");

Then the feature request came to be able to work with multiple databases at the same time (kind of "sharding"). The DB_INSTANCE singleton represented a single database, so this feature required tons of lines of code to be rewritten — the components now got the "db instance" injected into them.

Alex Shesterov
  • 26,085
  • 12
  • 82
  • 103
1

First, dependency injection is not java specific. This is a misconception. It's a good idea in lots of other languages. Separating glue code from business logic (which is what dependency injection is) is a good idea no matter what you use and a specific instance of separation of concerns. That's never a bad idea. You should do that in every language that you use. How you do this works different for different languages.

Second: DIY Dependency Injection is easy: it's a design pattern, not a framework. Though of course there are several good Java frameworks for this of course that you probably want to use. Writing glue code manually is monkey work. Automating that is a good idea.

The way this works is simply applying a few rules:

  1. Code modules/classes/objects/functions, etc. that contain business logic don't create anything that they need (aka dependencies) themselves. Instead everything they need is given to them via parameters (aka. injecting). In Java the best place to do this would be the constructor. Setter injection is also a thing but constructor injection is what you should be doing.
  2. Code that builds/constructs/initializes/configures like constructors, main methods, beforeTest methods etc. should not do work other than that: don't put business logic here. This is where glue code goes. Glue code should never mix with business logic.

That's it. Simple. Create stuff, inject it where it is needed. Do that consistently. If you find you need to inject a lot of stuff in one place, that's a coupling and cohesiveness problem: fix it because your design is broken.

There's nothing Java specific here. It's a logical consequence of applying SOLID principles. You cannot do that and NOT be doing dependency injection. You can do this in Javascript, Ruby, python, Haskell, lisp, etc. Every time you hear about code being hard to test or maintain, you'll find that people were mixing glue code and logic and made a big mess. Every one of those languages has good idioms for doing this.

Jilles van Gurp
  • 7,927
  • 4
  • 38
  • 46