in reply to Rethinking Your Program's If-Thens

Another way is to refactor them into four separate classes, based on your $dcr_type variable. A fifth class, would be used as a sort of factory and would decide which subclass to return based on the value of the $dcr_type. You would still have the if...then logic, but it is hidden by a separate layer of abstraction. It would go something like this (this is just an example, so the code below is very skimpy)

package factory; #We don't need any logic in this constructor, so... sub new { my $class = shift; bless {}, $class; } sub getInstance { my ($class, $dcr_type, @row) = ( $_[0], uc $_[1], @{$_[2]} ); if ($dcr_type eq "CONTACT"){ return contact->new(@row); } elsif($dcr_type eq "LITERATURE"){ return literature->new(@row); } elsif($dcr_type eq "FAQ"){ return faq->new(@row); } elsif($dcr_type eq "ORGANIZATION"){ return organization->new(@row); } } package contact; sub new {...} sub doTheDeed{ return ('HQ' , undef); } package literature; sub new {...} # @_row is this classes local version of the @row parameter sub doTheDeed{ return (undef, $_row[4]) } package faq; sub new {...} # @_row is this classes local version of the @row parameter sub doTheDeed{ return (undef, $_row[2] eq 'Service' ? $_row[3] : $_row[4]); } package organization; sub new {...} # @_row is this classes local version of the @row parameter sub doTheDeed{ my @ret = ($_row[2], undef); $ret[0] = 'HQ' if ($_row[0] eq 'Headquarters'); return @ret; }

Now your main body code will look like:

my $fact = factory->new(); my $instance = $fact->getInstance($dcr_type, @row); return $instance->doTheDeed();

Replies are listed 'Best First'.
Re: Re: Rethinking Your Program's If-Thens
by runrig (Abbot) on Oct 12, 2002 at 00:28 UTC
    All those if/elsif's make your code look somewhat like 'The Wrong Way' to do it according to the Patterns in Perl web site. I'm not sure how you would fit this problem into something resembling 'The Right Way' though I have an idea. If dcr_type is tainted, you'd have to make sure that it matches '^(CONTACT|FAQ|LITERATURE|ORGANIZATION)$', then assuming that you have those four classes defined, you can just call $dcr_type->new(@args). You could even do $dcr = s/(.*)/\u\L$1/ so you can have normal ucfirst type class names. Keep in mind I haven't really thought much about the OP's problem, so I don't know how appropriate any of this is for this particular case :-)
      It would be the wrong way if it were all one class. In this case, the if is in the factory class. In the example, there is one class who's behaviors change based on the values in the class. What I have above is a factory class deciding what subclass to return based on the value passed in. Each class, then, behaves differently.