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.