Kiss My App

Sunday, February 20, 2005

Container and Factory Seperation

I recently finished rewriting a simple container that uses Constructor Injection-- woohoo. I decided to create my own container because I wanted to be able to uniquely manage the lifecycles of a heirarchy of containers: Application, Session, and Request.

The idea is that you separate configuration from lifecycle management through the use of 'wormholes'. This means that objects from the top layer are passed to objects lower in the heirarchy, basically allowing customizations at the top level to act upon data at much lower layers via passed parameters in method calls.

CompositeFactory factory = ....
Container c = new Container(factory);
UserSaveAction action = c.create(UserSaveAction.class);

// the Container...
public <T> T create(Class<T> t, Object... p)
throws ActualizationException {
if (this.factory.contains(t)) {
// note 'this' is passed to factory
return this.factory.create(this, t, p);
} else if (this.parent != null) {
return this.parent.create(t, p);
}
throw new ActualizationException(...);
}

// the internal CompositeFactory reference
public <T> T create(Container c, Class<T> t, Object... p)
throws ActualizationException {
Factory<T> f = this.factories.get(t);
T result = null;
if (f != null) {
// Container passed again
result = f.create(c, p);
}
return result;
}

// within the Factory
public UserSaveAction create(Container c, Object[] p)
throws ActualizationException {
// Container used to wire objects together
UserDao dao = c.create(UserDao.class);
return new UserSaveAction(dao);
}

To take advantage of this layer managment, we seperate responsibilities between the container and the factory.

CompositeFactory cf = new CompositeFactory();
cf.add(new Factory(UserDaoImpl.class));
cf.add(new Factory(UserSaveAction.class));
cf.add(OrderController.FACTORY);

Container mine = new Container(cf);
Container yours = new Container(cf);

In the example above, both containers can act upon and use the CompositeFactory independently of each other. My Container could have it's own lifecycle, while your Container could have a different lifecycle. Ideally, I could pre-configure three different CompositeFactorys for each web scope and allow each user to declare their own Containers backed by their own Session or Request for lifecycle managment.

CompositeFactory app = new CompositeFactory();
CompositeFactory ses = new CompositeFactory();
CompositeFactory req = new CompositeFactory();

// initialize each factory in the appropriate scope

// only once at app initialization
ApplicationContainer appC =
new ApplicationContainer(servletContext, app);


// only once for each session
// pass the ApplicationContainer in as parent
SessionContainer sesC =
new SessionContainer(appC, httpSession, ses);


// for each request
// pass the SessionContainer in as parent
RequestContainer reqC =
new RequestContainer(sesC, httpRequest, req);



I really do enjoy constructor injection as it seems to solve a lot of problems that setter injection has in dealing with 'good citizen' principles. With constructors, when you 'new' and object, it's wired and ready to go. If you depend on various settters to be used, then you have to add code all over to gaurantee that supporting objects have been set before some operation can be made. This is sloppy coding IMHO.

In addition, by following 'single responsibility' principles, you start to write more reusable objects that are used in the construction of more complex objects that are founded on delegation and composition. Really, you reach a point in this style of coding where the requirement for dependency-injection containers kind of falls away.

1 Comments:

  • I worked through your example code, and noticed that you're not doing anything with the variable parameter list "p", though I assume those are how you'd specify the configuration for the dependent object.

    Question is, where do you configure the requisite objects that the dependent one needs? If these are not singletons, that would be a big complication.

    Does this make sense?

    By Anonymous Anonymous, at 6:43 PM  

Post a Comment

<< Home