note
jeffa
<p>
Just hanging around here inspires me to write all kinds of
code/snippets that i would never think of otherwise.
Going with Corion's [id://270198|advice] about the Facade
Pattern (<tt>brian d foy</tt> wrote an excellent Perl Review
[http://www.theperlreview.com/Issues/The_Perl_Review_0_4.pdf|article]
on that pattern by the way - you should read it), here is
my quick-n-dirty mini-tutorial:
</p>
<readmore>
<p>
Say you have a dynamic website whose content is driven by
a series of methods/functions contained in some library.
Currently, CGI.pm is being used to generate HTML. The
library (module) might look like:
<code>
package Old;
sub new {
my ($class,@arg) = @_;
my $self = {};
return bless $self,$class;
}
# pretend these return HTML pages generated via CGI.pm
sub index { "CGI.pm index page" }
sub page1 { "CGI.pm page1" }
sub page2 { "CGI.pm page2" }
sub page3 { "CGI.pm page3" }
1;
</code>
A cow-orker decides to rewrite these methods and use
HTML::Template instead:
<code>
package New;
sub new {
my ($class,@arg) = @_;
my $self = {};
return bless $self,$class;
}
# pretend these return HTML pages generated via HTML::Template
sub index { "H::T index page" }
sub page2 { "H::T page2" } # page 2 was easier than 1 ;)
1;
</code>
They haven't even finished, but the boss is so impressed
that (s)he asks you to go ahead and substitute the new
methods in. What do you do? You write another "layer" -
another module that <tt>use</tt>s both libraries and
delegates which library to use for a given method call. A
first naive (as all my first approaches usually are) might
look like:
<code>
package Interface;
use Old;
use New;
sub new {
my ($class,@arg) = @_;
my $self = {};
return bless $self,$class;
}
sub index { return New->new()->index }
sub page1 { return Old->new()->page1 }
sub page2 { return New->new()->page2 }
sub page3 { return Old->new()->page3 }
1;
</code>
Before i say why that is naive, here is the test script:
<code>
use strict;
use warnings;
use Interface;
my $obj = Interface->new;
print $_,$/ for map $obj->$_, qw(index page1 page2 page3);
</code>
Go ahead and create those 4 files and make sure everything
works. So why naive? Because you probably have more than
4 methods in you old library, many more. I myself am too
lazy correctly type in every single method ... why not just
use AUTOLOAD? (don't you wish C had one?) Much like the
anonymous list i used on the last line of the test script,
we could use a similar technique. Here is a revised
Interface.pm:
<code>
package Interface;
use Old;
use New;
use Carp;
sub new {
my ($class,@arg) = @_;
my $self = {};
return bless $self,$class;
}
my %new = map {$_ => 1} qw(index page3 page2);
sub AUTOLOAD {
my $self = shift;
my $name = $AUTOLOAD;
$name =~ s/.*://; # strip fully-qualified portion
#TODO: method name validation!
return $new{$name}
? eval "New->new->$name"
: eval "Old->new->$name"
;
}
sub DESTROY {} # good practice - prevents unecessary call to AUTOLOAD
1;
</code>
Now all you need to do is add the name of the methods to
<tt>%new</tt> as they are completed. Once Old.pm has been
completely deprecated you could get rid of Interface.pm.
<p>
By this point you must be asking how all of these name changes are going to affect users ... because they are!
In this example, i had the luxury of knowing ahead of time
what was going to happen, so i programmed to the
Interface.pm module. In reality, i would be programming to
the Old.pm module instead. My recommendation is to simply
rename the old library to something else, and name your
<i>Interface.pm</i> the original old lib name. Then, when
the old library has been completely deprecated (oxymoron?), rename the new library to the original old lib name.
</p>
Sounds easy, but i know it really isn't. It's hard work
no matter how you slice it, but if you provide a seamless
way for the lib users to continue to use old methods while
new ones are being implemented, then it's probably worth
it (er ... whatever <i>it</i> is ...).
</readmore>
<p>
Brushing up and writing about the Facade Pattern has nothing
to do with my current projects, but i somehow feel more
refreshed for doing something new and "not my job" ...
oh, and beating the crap outta my drums doesn't hurt either ;)
</p>
<p>jeffa</p>
<font size=1>
<pre>
L-LL-L--L-LL-L--L-LL-L--
-R--R-RR-R--R-RR-R--R-RR
B--B--B--B--B--B--B--B--
H---H---H---H---H---H---
(<a href="http://jeffa.perlmonk.org/tripdid.mp3">the triplet paradiddle with high-hat</a>)
</pre></font>
270194
270194