I want to build a bunch of Perl subrotines that all have the same template if elsif elsif else
that takes a decision based on a factor variable. Here's an example of subroutine template:
sub get_age{
my $factor=shift;
if ($factor == 1 ){ print "do something" }
elsif ($factor == 2 ){ print "do somthing2" }
elsif ($factor == 3 ){ print "do somthing3" }
elsif ($factor == 4 ){ print "do somthing4" }
else { print "error" }
}
I am wondering if there some design pattern on Perl to replace the if else
condition with more elegant solution which easy to maintain in the future specifically if I need to change some of the conditions or delete some of it?
A couple of people have mentioned a dispatch table. There are two things and it's nice to keep them apart sometimes. There's the list of possible things that could happen, and the thing that makes them happen. If you couple the two, you're stuck with your solution. If you keep them separate, you have more flexibility later.
The dispatch table specifies the behavior as data instead of program structure. Here's two different ways to do it. With your example you have integers and something like that might use an array to store things. The hash example is the same idea but looks up the behavior slightly differently.
Also notice that I factor out the print
. When you have repeated code like that, try to move the repeated stuff up a level.
use v5.10;
foreach my $factor ( map { int rand 5 } 0 .. 9 ) {
say get_age_array( $factor );
}
my @animals = qw( cat dog bird frog );
foreach my $factor ( map { $animals[ rand @animals ] } 0 .. 9 ) {
say get_age_hash( $factor );
}
sub get_age_array {
my $factor = shift;
state $dispatch = [
sub { 'Nothing!' }, # index 0
sub { "Calling 1" },
sub { 1 + 1 },
sub { "Called 3" },
sub { time },
];
return unless int $factor <= $#$dispatch;
$dispatch->[$factor]->();
}
sub get_age_hash {
my $factor = shift;
state $dispatch = {
'cat' => sub { "Called cat" },
'dog' => sub { "Calling 1" },
'bird' => sub { "Calling 2, with extra" },
};
return unless exists $dispatch->{$factor};
$dispatch->{$factor}->();
}
Update: Make sure you read brian's comment below; basically, it's better to use for
instead of given
, due to various issues he comments on in his link. I've updated my advice to incorporate his improvements, which he outlines in Use for() instead of given():
If you're on perl 5.10 or newer, given/when
is the magic pair you are looking for, but you really should use for/when
instead.. Here's an example:
use strict;
use warnings;
use feature qw(switch say);
print 'Enter your grade: ';
chomp( my $grade = <> );
for ($grade) {
when ('A') { say 'Well done!' }
when ('B') { say 'Try harder!' }
when ('C') { say 'You need help!!!' }
default { say 'You are just making it up!' }
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With