Container Dependency

Symptoms

Classes that depend on the container.

Consider the following example. We have a class BImpl that requires an A instance. It declares the dependency on the container so it can look up that A:

public interface A {
}

public class AImpl implements A {
}

public class BImpl implements B {
    private final A a;

    public BImpl(PicoContainer pico) {
        a = (A) pico.getComponentOfType(A.class);
        
        /*
        alternatively:
        a = (A) pico.getComponent("a");
        */
    }
}

The usage would probably look similar to:

MutablePicoContainer pico = new DefaultPicoContainer();
pico.addComponent("a", AImpl.class);
pico.addComponent("b", BImpl.class);
pico.addComponent(pico);

...
B b = (B) pico.getComponent("b");

It will work, but it is an antipattern.

The reasons why the above implementation of BImpl is an antipattern are:

  • It introduces an unneeded dependency from BImpl to the container, breaking the core principal of Inversion of Control
  • This makes BImpl harder to unit test
  • B assumes that the container has a registered an A. As a result, B won't fail fast if it has not. Instead, a will reference null, and BImpl will fail later.

Causes

  • Missing the historical context of PicoContainer, Dependency Injection and Inversion of Control.
  • Love of 'God class' designs.

What to do

The simple and elegant solution to this antipattern is not to complicate the world more than it is.

Here is how it should be:

public class BImpl implements B {
    private final A a;

    BImpl(A a) {
        this.a = a;
    }
}

PicoContainer will figure out that BImpl needs an A instance, and will pass in the AImpl, as this is an implementation of A.

The One Major Exception

When you go to integrate all your components into a single application, SOMETHING is going to have to wire all these components together. In Pico-land, we call that the "bootstrap" script. (Script, is a loose term, it could easily be a reference to PicoContainer inside a class' main() function.) The pattern of this code will often look like this:

public class Bootstrap {
	
   private PicoContainer pico = new PicoBuilder().withLifecycle().withCaching().build();


	public static void main(String[] args) {
		Bootstrap bootstrap = new BootStap();
		bootstrap.start();
	}


	public void start() {
		/*  pico.addComponent(A.class), pico.addComponent(B.class) */
		/*  etc. */

		
		pico.start();
		//enter some sort of event loop.


		//Event loop broken.

  		pico.stop(); 
 	}


	public void stop() {
		pico.stop();
		pico.dispose();
	}
}

PicoContainer has a sample project called "bootstrap" that does just this sort of thing. For web applications, Pico uses a WebappContextListener to bootstrap an application-level container, and a Servlet filter to bootstrap a request-level container.