Is Dependency Injection Replacing the Factory Patterns?

Jakob Jenkov
Last update: 2014-05-25

Dependency Injection (DI) has been a hot topic since at least 2003 and onwards. Lots of dependency injection frameworks have appeared (including my own Butterfly DI Container), and lots of forums and blogs has discussed the technique. Yet I still experience big enterprise software development departments, who have not yet embraced the idea. Instead I see them using the Factory design patterns extensively in situations when dependency injection would have been a far more flexible solution to the same problem.

Of course this is sometimes the case when old code is being maintained, which was written, or at least started, before dependency injection became mainstream. The factory pattern is then adhere to for consistency with the old code. But sometimes I also see the factory pattern used in completely new code.

This text will show how dependency injection is the next evolutionary step after the Factory design patterns, in the persuit of loosely coupled components.

The Purpose of the Factory Design Patterns

The purpose of the factory patterns is to separate the use of a certain component, from the choice of implementation + instance management of that component. These three separate concerns are repeated here:

  • Component Use
  • Component Implementation Choice
  • Component Instance management

In the following sections I will show how the factory patterns achieve the separation of these concerns.

Static Factory

The static factory hides the choice of implementation and instance management of a certain component, from the objects using this component.

Here is first an example of how the code would look without a static factory:

public class MyClass {

  IMyComponent component = new MyComponent();

  public void myMethod(){
    component.doSomething();
  }
}

The IMyComponent is an interface which is implemented by the MyComponent class. In this example the MyClass depends on the concrete implementation of IMyComponent - the MyComponent class. It also has hardcoded, that a new instance of MyComponent is created every time a MyClass instance is created.

To decouple MyClass class from MyComponent you can separate them by a static factory. Here is an example of a factory called MyComponentFactory:

public class MyComponentFactory {

  public static IMyComponent instance(){
    return new MyComponent();
  }
}

And here is the MyClass using the factory instead of instantiating MyComponent directly:

public class MyClass {

  IMyComponent component = MyComponentFactory.instance();

  public void myMethod(){
    component.doSomething();
  }
}

Now MyClass doesn't know what implementation of IMyComponent it gets, nor if it's a new or cached instance.

Abstract Factory

The static factory design still has a few drawbacks though. What if you want to be able to switch the implementation at runtime? In other words, you want to be able to switch the factory at runtime. In addition you want to be able to use different factories in action from within different components. This design doesn't allow that.

To solve this problem you can use the abstract factory pattern instead of the static factory pattern. Rather than calling a static instance() method you first obtain a factory of a certain kind, and then ask that factory for instances. Here is how the MyClass class could look after that little change:

public class MyClass {

  IMyComponent component = null;

  public MyClass() {
    IMyComponentFactory factory =
            MyComponentFactoryManager.getFactory("A");

    component = factory.instance();
  }

  public void myMethod(){
    component.doSomething();    
  }
}

And here is how the corresponding MyComponentFactoryManager and IMyComponentFactory interface would look:

public interface IMyComponentFactory {
  IMyComponent instance();
}
public class MyComponentFactoryManager {

  private static Map<String, IMyComponentFactory> factories =
      new HashMap<String, IMyComponentFactory>();

  public static setFactory(
       String factoryId, IMyComponentFactory factory){

    factories.put(factoryId, factory);
  }

  public static IMyComponentFactory getFactory(String factoryId){
    return factories.get(factoryId);
  }
}

As you can see, it is now possible to add, replace and remove factories at runtime. Smart, eh?

But even the abstract factory pattern has a drawback: The factory id is hard coded inside the MyClass! If both a MyClassA and MyClassB was referring to factory "A", then replacing factory "A" in the MyComponentFactoryManager class would affect both MyClassA and MyClassB. Unless, of course, you execute the factory replacement just before activating either MyClassA or MyClassB, and set the factory back to what it was, just prior to the factory replacement. But that kind of stuff gets clumsy.

In addition, MyClass still depends on the MyComponentFactoryManager class to obtain it's instance, AND the IMyComponentFactory interface to obtain a IMyComponent instance. Actually, the IMyComponent instance was all the MyClass class was ever interested in, but now it is forced to know and extra class (MyComponentFactoryManager) and an extra interface (IMyComponentFactory) to get to the IMyComponent instance. Clumsy, clumsy, clumsy!

The ServiceLocator Pattern

If you are familiar with the ServiceLocator design pattern you will notice that this pattern is very similar to the Factory pattern, and thus has the same problems.

Describing the ServiceLocator pattern is outside the scope of this text, since I'll describe what I believe to be a better solution anyways: Dependency Injection. To get more information about the ServiceLocator pattern, do a google search on it.

How Dependency Injection Solves the Problem

When using dependency injection the responsibility of obtaining needed instances is reversed. A class no longer obtains these instances itself. Instead, a dependency injection container creates the needed instances, and "injects" them into the object.

Here is how MyClass would look when prepared for dependency injection (in its constructor):

public class MyClass {

  IMyComponent component = null;

  public MyClass(IMyComponent componentImpl) {
    component = componentImpl;
  }

  public void myMethod(){
    component.doSomething();
  }
}

Now MyClass doesn't know anything about the factory classes anymore. It only knows about the IMyComponent interface. It doesn't either know whether the injected IMyComponent instance is a new instance or a cached instance. You can also easily switch the implementation injected into e.g. class MyClassA and MyClassB independently from each other.

Additionally, as a side effect MyClass has been easier to unit test because you can now inject a mock (fake) IMyComponent instance into it, during unit testing. The mock object can then record what methods the MyClass calls on it, and your unit test can then check if the methods were called as expected.

Of course the drawback of this approach is that you now need to configure the dependency injection container to inject the IMyComponent instances into the MyClass instances. Here is a configuration example using Butterfly DI Container's configuration script language, Butterfly Container Script:

myComponent = * com.myapp.MyComponent();
myClass     = * com.myapp.MyClass(myComponent);

First an "object factory" called "myComponent" is defined. It returns a new instance of com.myapp.MyComponent() every time that factory is called. The * means "new instance".

Second an object factory called "myClass" is defined. This is also defined as a "new instance" per factory call. Into the MyClass constructor is injected an instance of whatever the "myComponent" factory returns when calling it (which is a new instance of MyComponent). So, when you ask the container for a "myClass" instance the container first creates a "myComponent" instance, then injects it into the constructor of a MyClass instance, as configured in the "myClass" factory. Smart, isn't it?

Finally I'll just show how you obtain a "myClass" instance once the container is configured:

MyClass myClassInstance = (MyClass) container.instance("myClass");

Pretty simple.

Summary

As you can see, a class prepared for dependency injection is much cleaner, and easier to test, than a class using any of the factory patterns. It is also easier to switch what is injected into different classes which use the same interfaces.

The drawback of dependency injection is that you need a dependency injection container, and you need to configure it. However, you can have so many benefits from a dependency injection container in addition to just cleaner code, that I really think it is worth it!

Jakob Jenkov

Featured Videos

Java Generics

Java ForkJoinPool

P2P Networks Introduction



















Close TOC
All Tutorial Trails
All Trails
Table of contents (TOC) for this tutorial trail
Trail TOC
Table of contents (TOC) for this tutorial
Page TOC
Previous tutorial in this tutorial trail
Previous
Next tutorial in this tutorial trail
Next