This post originated from an RSS feed registered with Java Buzz
by Chris Winters.
Original Post: Using a lot lately: Factory + implementation autodiscovery
Feed Title: cwinters.com
Feed URL: http://www.cwinters.com/search/registrar.php?domain=jroller.com®istrar=sedopark
Feed Description: Chris Winters on Java, programming and technology, usually in that order.
If you're not using IoC and
you want decoupled code while still figuring out at runtime how to
perform a particular action you've probably got a number of factories
in your application. But how to let your factory know about all the
implementations it can create?
Using Class::Factory
you can add classes to the factory dynamically like this:
# declare the factory:
package My::Factory:
use base qw( Class::Factory );
# and add classes to it from elsewhere:
My::Factory->register_factory_type( hat => 'My::Factory::Hat' );
My::Factory->register_factory_type( ascot => 'My::Factory::Ascot' );
And using Module::Find
you can find all the classes to add to the factory at runtime with
something like this:
use Module::Find;
useall( 'My::Factory' );
(NB: I haven't used M::F but have my own implementation of
something that appears to do exactly the same thing.)
So why not have all the subclasses register themselves with
the factory?
package My::Factory::Hat;
use base qw( My::Factory );
My::Factory->register_factory_class( hat => __PACKAGE__ );
And then have the factory find all its implementations?
package My::Factory:
use base qw( Class::Factory );
use Module::Find;
useall( __PACKAGE__ );
Those two simple steps create a system where a user can just drop a
class in the right place and have it found by your framework. This is
particularly useful if your set of objects gets collected and run
together (using some additional metadata for ordering if necessary) as
in my discussion
of OpenInteract2::Setup a few weeks ago. There, a user can just
add a class with the right name and dependencies (the metadata) and
when the website starts up it gets found, imported, and executed in
the right order.
Or in another example that I'm not quite done with: how do we
associate an incoming URL (or some other identifier) with the action
object responsible for generating its content?
Currently this is touched in a couple of places, always a bad
smell. The request
is responsible for parsing the URL into action and task names and then
the controller (underdocumented in last release) uses this name to create the action. But the request doesn't
know anything about actions -- it got put there just because we were
already parsing URLs and it seemed appropriate to extract a little more data there.
So why not let a separate object figure this out? This whole thing
got started because I wondered how hard it would be to create userdirs
like the CPAN urls in the last paragraph -- that could just be one of
the objects in a chain of responsibility that looks at the URL (or
whatever else it wants) and decides what action to create.
Like I said, I'm not done with it yet. But the factory plus
autodiscovery pattern makes this a snap to implement and test
out. Even better, it will be extremely easy for other people using
OpenInteract2 to add their own behaviors that are indistinguishable from
the internal ones to perform this core job.