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:
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.
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.