New is the new goto

I really like this catchphrase! While I’m pretty sure I’ve read it somewhere, Google-searching it only points to Adventures in Software. Why is instantiating a class using the new keyword usually as bad thing? For two reasons:

  • It ties two implementation classes strongly together. You will have a hard time testing one class in isolation or changing its behavior without modifying it.
  • It  hides the dependency somewhere in your code. The dependencies of a class are not obvious if there are new statements scattered all over the place.

A simple approach

Without going into much detail (there is a lot of literature about it), here’s a simple strategy to avoid new statements:

  • pass in all the dependencies of a class as constructor arguments and assign them to private final fields
  • make the types of the constructor arguments interfaces, not classes
  • do all the instantiation work in dedicated factory classes (or using a dependency injection framework)

Here’s a synthetic example:

public class Foo {
    private final IFooCollaborator fooCollaborator;

    public Foo(final IFooCollaborator fooCollaborator) {
        this.fooCollaborator = fooCollaborator;
    }
}

The number of constructor arguments will show you the exact number of collaborators. This is a very valuable hint about your design quality. If you have too many (real) collaborators, your class either does too much, or does something at too low a level of abstraction. In this case, consider combining some of the collaborators into a new class. If your class uses a collaborator just to obtain some other class, it is not a real collaborator, and your design is flawed.

Wiring it up

Of course, your new keywords will have to go somewhere. Because after all, you will need to bind concrete implementations to your interfaces. If you don’t use some kind of dependency injection framework, this will be done in factory classes. They are responsible for building object graphs (wiring collaborators), and this responsibility is cleanly separated from your business logic code. See the classic “Where Have All the Singletons Gone?” for more about this topic.

Some related anti-patterns

Of course, you could avoid using new statements by calling static factory methods or some global (Singleton) getInstance method. We all know this is bad, bad, bad, bad. Using the Service Locator or Service Registry pattern isn’t much better. Using some registry object (or even worse, static methods of a registry class) will hide your dependencies. And it will make almost every class dependent of your registry, even though it is not a real collaborator but just used to obtain the actual collaborators.

Exceptions to the rule

Of course there are exceptions to the rule. Value objects, exception objects, or data transfer objects are examples of objects whose direct creation you might accept. And you might accept directly instantiating runtime or standard library classes (think Date and String). But reconsider your abstractions when thinking about instantiating something like FileInputStream.

What about Dependency Injection?

I prefer constructor injection over setter injection. The Spring Framework does the opposite. I think it is much more explicit to have all collaborators listed as constructor arguments and assign them to final fields. Again, Miško Hevery explains the advantages of this approach very well.

If you use Enterprise Java Beans, you can have collaborators injected by annotating a field with @EJB:

@Stateless 
public class MyClass implements IMyClass {
    @EJB
    private DaoFactoryLocal daoFactory;

    public MyClass() {}

    public MyClass(final DaoFactoryLocal daoFactory) {
        this.daoFactory = daoFactory;
    }
}

Unfortunately, being an EJB itself, MyClass will have to provide a no-argument constructor, and therefore you cannot mark your collaborator fields final. But I still recommend having a second constructor listing all collaborators, for the reasons stated above.

You may also like...