Thanks for the comment.
Background is that we have a Database class, with generally (everyday) used SQL, and additional specialised sub-classes containing domain specific SQL - i.e. SQL specific to some rarely used nook. Database instantiation is handled a long way off, and $db is passed around (a little like a baby needing burping!). It has lots of stuff built in like which server to connect to for a database, a pool of connection handles, whether to allow remote connections, other bits of context etc.
Suggestion 1: is kind-of what we had - but we stored $db on $self during instantiation. The problem is that other processing is going on, and we want various contexts to be able to interchangably use $db / $special_db / $even_more_special_db as database objects. This would mean that we would have to implement all the methods of $db (or use autoload)
Suggestion 2: is not a runner, as the $db instance is created a long way off, and many moons before we get passed it. Also, this doesnt work when in one context we want colour_specials and in another we want to switch to garden_specials which are orthogonal. (ie Database specials are siblings - they cant/dont inherit from each other)
In the end, we dug up our Head First Design Patterns, and implemented a Decorator, using AUTOLOAD to despatch methods not found on the specialised class.
We end up with this sort of thing:
# each Database::XXX class decorates the database
# arg passed during instantiation, and any methods it
# doesnt recognise are passed through to the decorated
# database.
# All done by making the Database:XXX classes inherit
# from our Decorator class.
# This code illustrates how this looks to users
# of the database classes.
my $db = Database->new( database => 'sussex' );
# add colour managment sprocs to database
my $colour_db = Database::Colour->new( db => $db );
# Database::Colour knows hues hue (implements Rainbows)
$colour_db->generateRainbow();
...
checkFlowerColours( db => $colour_db );
sub checkFlowerColours {
my %arg = @_;
# in this context, we need to add some
# garden compost to the colour enabled database
my $garden_db = Database::Garden->new( db => $arg{db} );
# sameColour is from Database::Colour
if ( $garden_db->sameColour( $garden_db->getLawnColour(), 'brown'
+) {
# action is from Database::Garden
# but hosePipeBan is from Database('sussex')
$garden_db->waterPlants()
unless $garden_db->hasHosePipeBan();
}
}
Yeah, I know its a skanky example, but you get the Decorator like pattern idea. And the decorated $db just has special funcs for the scope of the block where it is created. I will post a cut-down Decorator class if anyone is interested?
|