Dependency injection refers to a template that tells the class what its dependencies will be, rather than requiring the class to know where to find all 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(...); } }
something like that:
public class UserFetcher { private final DbConnection conn; public UserFetcher(DbConnection conn) { this.conn = conn; } public List<User> getUsers() { return conn.fetch(...); } }
This reduces code cohesion, which is especially useful if you want to run the UserFetcher unit test. Now instead of UserFetcher always working with the database found in 10.167.1.25 , you can pass DbConnection to the test database. Or, even more useful in quick testing, you can pass an implementation or subclass of DbConnection that doesn't even connect to the database, it just drops the requests!
However, this kind of primitive implementation of dependencies complicates the connection (providing the object with its dependencies), because you replaced access to the dependency with a global variable (or a locally created object) with the transfer of dependencies throughout the graph of the object.,
Recall the case when UserFetcher is an AccountManager dependency, which is an AdminConsole dependency. Then the AdminConsole needs to pass the DbConnection instance to the AccountManager , and the AccountManager to pass it to the UserFetcher ... even if neither the AdminConsole nor the AccountManager should use DbConnection directly!
Inversion of the control container (Spring, Guice, etc.) It is designed to simplify the implementation of dependencies by automatically connecting (providing) dependencies. To do this, you once tell the IoC container how to provide the object (in Spring it is called a bean), and whenever another object requests this dependency, it will be provided by the container.
So our last example might look like this with Guice if we were to use the injection constructor:
public class UserFetcher { private final DbConnection conn; @Inject
And we must configure the IoC container. In Guice, this is done through an implementation of Module ; spring you customize the 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 Guice or Spring, DbConnection provided automatically.
Guice has a really good wiki article on the motivation for dependency injection and continued use of the IoC container. It is worth reading to the end.
A strategy template is just a special case of dependency injection when you enter logic instead of an object (although in Java the logic will be encapsulated in the object). This is a way to branch 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 want to distribute this code in a new jurisdiction with a different sales tax scheme? You can enter logic for calculating tax, for example 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; }