[Chicago-talk] Class::Factory, One more question

Jim Thomason jthomasoniii at yahoo.com
Sat Mar 20 11:24:50 CST 2004


Ahh, the abstract factory pattern. One of my personal
favorites in my bag of tricks. I can never recall the
difference between abstract and concrete factory
patterns, though, so this might be a normal factory.

Anywho...it's extremely useful when you know that
you're going to need a particular type of object, but
not which particular subclass it is you'll need. Say
you have a user interface where the user selects a
piece of fruit. You don't know what it is in advance,
but you'll need to access info on it later. You can
put a big if/then/else into your code to check what
comes in.

use Fruit;
use Fruit::Apple;
use Fruit::Orange;
#etc.

if ($choice eq 'Apple') {
  $fruit = Fruit::Apple->new();
} elsif ($choice eq 'Orange') {
  $fruit = Fruit::Orange->new();
}
 
etc.
 
It scales poorly. When you need to add new fruit, you
have to alter all of your ladders. With a factory, you
just register the type somewhere.

#in some module, conf file, etc., someplace else:
$factory->register('orange', 'Fruit::Orange');

Then your code is simply:

$fruit = Fruit->object_of_type($choice);
 
voila!

For a more concrete example, I have an applications
framework running my site (www.jimandkoka.com). it
also runs a few other sites (www.themensroom.net,
www.lunchmanager.com). Some of the individual
applications are on only one site (my biking log), but
some are on all sites (the poll application, for
instance). Other things are global everywhere, such as
users and groups. But the users are slightly different
on the 3 systems. The Lunch manager needs users to be
able to choose to receive email, TMR needs users to
register their ISCA username, my site needs none of
those. Now, the polling application doesn't care about
any of those extra doohickeys, it just cares about the
basic stuff.

Now, I don't want to have to alter the polling app for
each site, replacing my login validation checks with
the individual modules (JIM::User, TMR::User, and
Lunch::User, in this case). That gets messsy. Then if
I ever want to put my polling app someplace else, I
have to re-do another branch with another set of
modules.

One solution is to just use the superclass (JIM::User,
in this case), since it doesn't care about the extra
thingys anyway. Still, that locks it into using users
that subclass off of JIM::User, which may not be
desired. As long as the interface is the same, it
shouldn't care what the User objects are.

So my solution is to use a factory method. My calls go
from:

JIM::User->login_via_web();
to 
JIM::Object->class_for_type('user')->login_via_web();

Sure, I still need to use JIM::Object, but the polling
app uses it anyway, so no big deal. Just specify the
user type in the conf file, and then I can change the
actual object anytime I want (or as I'm doing, use
different objects on different sites) and never need
to touch the code.

It's great at allowing disparate components to
communicate w/o directly knowing what they're talking
to.

-Jim....
--- Jay Strauss <me at heyjay.com> wrote:
> One more question before I head into the office
> 
> I saw someone (on CDBI) mention class::factory.  I
> read the doc but don't
> really get it (though it looks like it might be
> neat).  Can someone explain
> when/why you'd use Class::Factory?
> 
> Thanks
> Jay
> 
> _______________________________________________
> Chicago-talk mailing list
> Chicago-talk at mail.pm.org
> http://mail.pm.org/mailman/listinfo/chicago-talk


__________________________________
Do you Yahoo!?
Yahoo! Finance Tax Center - File online. File on time.
http://taxes.yahoo.com/filing.html



More information about the Chicago-talk mailing list