Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Inversion of Control, Dependency Injection and Strategy Pattern with examples in java

I am often confused by these three terms. These three look similar to me. Can someone please explain them to me clearly, with examples.

I have seen similar posts and don't understand completely.

like image 529
Java P Avatar asked Sep 22 '12 05:09

Java P


2 Answers

Dependency Injection refers to the pattern of telling a class what its dependencies will be, rather than requiring the class to know where to find all of its dependencies.

So, for example, you go from this:

public class UserFetcher {
   private final DbConnection conn = 
      new DbConnection("10.167.1.25", "username", "password");

   public List<User> getUsers() {
      return conn.fetch(...);
   }
}

to something like this:

public class UserFetcher {
   private final DbConnection conn;

   public UserFetcher(DbConnection conn) { 
      this.conn = conn;
   }

   public List<User> getUsers() {
      return conn.fetch(...);
   }
}

This reduces coupling in the code, which is especially useful if you want to unit test UserFetcher. Now, instead of UserFetcher always running against a database found at 10.167.1.25, you can pass in a DbConnection to a test database. Or, even more useful in a fast test, you can pass in an implementation or subclass of DbConnection that doesn't even connect to a database, it just discards the requests!

However, this sort of primitive dependency injection makes wiring (providing an object with its dependencies) more difficult, because you've replaced accessing the dependency using a global variable (or a locally instantiated object) with passing the dependency around through the whole object graph.

Think of a case where UserFetcher is a dependency of AccountManager, which is a dependency of AdminConsole. Then AdminConsole needs to pass the DbConnection instance to AccountManager, and AccountManager needs to pass it to UserFetcher...even if neither AdminConsole nor AccountManager need to use the DbConnection directly!

An inversion of control container (Spring, Guice, etc) aims to make dependency injection easier by automatically wiring (providing) the dependencies. To do this, you tell your IoC container once how to provide an object (in Spring, this is called a bean) and whenever another object asks for that dependency, it will be provided by the container.

So our last example might look like this with Guice, if we used constructor injection:

public class UserFetcher {
   private final DbConnection conn;

   @Inject //or @Autowired for Spring
   public UserFetcher(DbConnection conn) { 
      this.conn = conn;
   }

   public List<User> getUsers() {
      return conn.fetch(...);
   }
}

And we have to configure the IoC container. In Guice this is done via an implementation of Module; in Spring you configure an application context, often through XML.

public class MyGuiceModule extends AbstractModule {    
    @Override
    public void configure() {
       bind(DbConnection.class).toInstance(
           new DbConnection("localhost", "username", "password"));
    }
}

Now when UserFetcher is constructed by Guice or Spring, the DbConnection is automatically provided.

Guice has a really good Wiki article on the motivation behind dependency injection, and further using an IoC container. It's worth reading all the way through.

The strategy pattern is just a special case of dependency injection, where you inject logic instead of an object (even though in Java, the logic will be encapsulated in an object). It's a way of decoupling independent business logic.

For example, you might have code like this:

public Currency computeTotal(List<Product> products) {
   Currency beforeTax = computeBeforeTax(products);
   Currency afterTax = beforeTax.times(1.10);
}

But what if you wanted to extend this code to a new jurisdiction, with a different sales tax scheme? You could inject the logic to compute the tax, like this:

public interface TaxScheme {
    public Currency applyTax(Currency beforeTax);
}

public class TenPercentTax implements TaxScheme {
    public Currency applyTax(Currency beforeTax) {
        return beforeTax.times(1.10);
    }
} 

public Currency computeTotal(List<Product> products, TaxScheme taxScheme) {
    Currency beforeTax = computeBeforeTax(products);
    Currency afterTax = taxScheme.applyTax(beforeTax);
    return afterTax;
}
like image 173
Mark Peters Avatar answered Sep 19 '22 00:09

Mark Peters


Inversion of control means that a runtime framework wires all components together (for example Spring). Dependency injection is a form of IoC (I don't know if another form of IoC exists) (see: http://en.wikipedia.org/wiki/Inversion_of_control).

Strategy pattern is a design pattern (defined by the GoF) where the algorithm can be replaced by another (see: http://en.wikipedia.org/wiki/Strategy_pattern). This is archived by provided several implementation of a same interface. When using an IoC like Spring, if you have several implementations of an interface, and if you can switch from an implementation to another by configuration, you are using the strategy pattern.

like image 43
funkygono Avatar answered Sep 19 '22 00:09

funkygono