loading...

Effective Java Tuesday! Prefer Dependency Injection!

kylec32 profile image Kyle Carter ・3 min read

Effective Java Review (36 Part Series)

1) Effective Java Tuesday! Let's Consider Static Factory Methods 2) Effective Java Tuesday! The Builder Pattern! 3 ... 34 3) Effective Java Tuesday! Singletons! 4) Effective Java Tuesday! Utility Classes! 5) Effective Java Tuesday! Prefer Dependency Injection! 6) Effective Java Tuesday! Avoid Creating Unnecessary Objects! 7) Effective Java Tuesday! Don't Leak Object References! 8) Effective Java Tuesday! Avoid Finalizers and Cleaners! 9) Effective Java Tuesday! Prefer try-with-resources 10) Effective Java Tuesday! Obey the `equals` contract 11) Effective Java Tuesday! Obey the `hashCode` contract 12) Effective Java Tuesday! Override `toString` 13) Effective Java Tuesday! Override `clone` judiciously 14) Effective Java Tuesday! Consider Implementing `Comparable` 15) Effective Java Tuesday! Minimize the Accessibility of Classes and Member 16) Effective Java Tuesday! In Public Classes, Use Accessors, Not Public Fields 17) Effective Java Tuesday! Minimize Mutability 18) Effective Java Tuesday! Favor Composition Over Inheritance 19) Effective Java Tuesday! Design and Document Classes for Inheritance or Else Prohibit It. 20) Effective Java Tuesday! Prefer Interfaces to Abstract Classes 21) Effective Java! Design Interfaces for Posterity 22) Effective Java! Use Interfaces Only to Define Types 23) Effective Java! Prefer Class Hierarchies to Tagged Classes 24) Effective Java! Favor Static Members Classes over Non-Static 25) Effective Java! Limit Source Files to a Single Top-Level Class 26) Effective Java! Don't Use Raw Types 27) Effective Java! Elminate Unchecked Warnings 28) Effective Java! Prefer Lists to Array 29) Effective Java! Favor Generic Types 30) Effective Java! Favor Generic Methods 31) Effective Java! Use Bounded Wildcards to Increase API Flexibility 32) Effective Java! Combine Generics and Varargs Judiciously 33) Effective Java! Consider Typesafe Hetergenous Containers 34) Effective Java! Use Enums Instead of int Constants 35) Effective Java! Use Instance Fields Instead of Ordinals 36) Effective Java! Use EnumSet Instead of Bit Fields

We have now arrived at item five from Effective Java. The topic of discussion today is about dependency injection. So let's dive into what dependency injection is. Dependency injection serves as a method of dealing with dependencies of an object. There are various ways of dealing with this problem, let's go through them and see what benefits dependency injection gives us.

One method would be to use a static utility. Let's see what that could look like:

The first option we are going to look at is a static utility class:

public class DoStuffService {
   private final static Repository repository = ...;

   private DoStuffService() {} // So no one can accidentally instantiate this class.

   public static Object getStuff() {
     return repository.getTopOne();
   }
}

another similar option is to use a singleton:

public class DoStuffService {
   private final Repository repository = ...;

   private DoStuffService(...) { }
   public static INSTANCE = new DoStuffService(...);

   public Object getStuff() {
     return repository.getTopOne();
   }
}

So what problems do these options cause us? Well both of these options suffer from the same issue. They are inflexible. What happens if you want to change out how the service gets it's data? What if we wanted to write a test where the datastore that the service is using is mocked out? How would we do this? So how can we solve this? Well it's pretty simple, simply pass the dependency into the constructor. This simple change adds a whole lot of flexibility to the code. Now if we wanted to change out the data store at runtime we simply pass in a different repository that meets the correct interface. If we need to write a test we can simply mock out the repository and focus on testing the behavior service. So what would our above example look like:

public class DoStuffService {
   private final Repository repository;

   public DoStuffService(Repository repository) {
      this.repository = repository;
   }

   public Object getStuff() {
     return repository.getTopOne();
   }
}

As mentioned in Effective Java a lot of people accidentally end up implementing this pattern without realizing they are doing it. That to me is a sign of a very good pattern. Now if you do this throughout your whole system and if it is a large system this can get a bit unwieldy. This is where dependency injection frameworks such as Spring come in. What these frameworks handle for you is the wiring of all the pieces together. If you are following the pattern above adding one of these frameworks should be fairly easy.

Something to be aware of though is there are ways that you can use dependency injection frameworks in a way that doesn't use dependency injection (weird right!?). For example look at this option:

public class DoStuffService {
   private final Repository repository;

   @Autowired
   public DoStuffService(Repository repository) {
      this.repository = repository;
   }

   public Object getStuff() {
     return repository.getTopOne();
   }
}

vs

public class DoStuffService {
   @Autowired
   private Repository repository;

   public DoStuffService() {
   }

   public Object getStuff() {
     return repository.getTopOne();
   }
}

Spring will allow you to do the second option and will inject the dependency in the member variable. That being said they do discourage the above option and we can see why with the above example and how much flexibility they bring.

So there you have it, a super quick intro to dependency injection. This is definitely a pattern I use very often and have great success with. How about you? How has this pattern worked for you?

Effective Java Review (36 Part Series)

1) Effective Java Tuesday! Let's Consider Static Factory Methods 2) Effective Java Tuesday! The Builder Pattern! 3 ... 34 3) Effective Java Tuesday! Singletons! 4) Effective Java Tuesday! Utility Classes! 5) Effective Java Tuesday! Prefer Dependency Injection! 6) Effective Java Tuesday! Avoid Creating Unnecessary Objects! 7) Effective Java Tuesday! Don't Leak Object References! 8) Effective Java Tuesday! Avoid Finalizers and Cleaners! 9) Effective Java Tuesday! Prefer try-with-resources 10) Effective Java Tuesday! Obey the `equals` contract 11) Effective Java Tuesday! Obey the `hashCode` contract 12) Effective Java Tuesday! Override `toString` 13) Effective Java Tuesday! Override `clone` judiciously 14) Effective Java Tuesday! Consider Implementing `Comparable` 15) Effective Java Tuesday! Minimize the Accessibility of Classes and Member 16) Effective Java Tuesday! In Public Classes, Use Accessors, Not Public Fields 17) Effective Java Tuesday! Minimize Mutability 18) Effective Java Tuesday! Favor Composition Over Inheritance 19) Effective Java Tuesday! Design and Document Classes for Inheritance or Else Prohibit It. 20) Effective Java Tuesday! Prefer Interfaces to Abstract Classes 21) Effective Java! Design Interfaces for Posterity 22) Effective Java! Use Interfaces Only to Define Types 23) Effective Java! Prefer Class Hierarchies to Tagged Classes 24) Effective Java! Favor Static Members Classes over Non-Static 25) Effective Java! Limit Source Files to a Single Top-Level Class 26) Effective Java! Don't Use Raw Types 27) Effective Java! Elminate Unchecked Warnings 28) Effective Java! Prefer Lists to Array 29) Effective Java! Favor Generic Types 30) Effective Java! Favor Generic Methods 31) Effective Java! Use Bounded Wildcards to Increase API Flexibility 32) Effective Java! Combine Generics and Varargs Judiciously 33) Effective Java! Consider Typesafe Hetergenous Containers 34) Effective Java! Use Enums Instead of int Constants 35) Effective Java! Use Instance Fields Instead of Ordinals 36) Effective Java! Use EnumSet Instead of Bit Fields

Posted on by:

kylec32 profile

Kyle Carter

@kylec32

Backend Architect at MasterControl

Discussion

markdown guide
 

Nice post, thanks!

I like the Dependency Injection pattern.

When I was doing Android, I didn't like so much the Dependency Injection frameworks, namely Google Dagger which in my opinion brings a lot of complexity and is poorly documented. As a consequence you see people investing weeks and months before they get to the point "ah ah, now I really understand dagger". Not worth it I would say.

I ended up writing how you don't need a framework to implement the pattern

Those days though I would recommend using insert-koin.io