in reply to replace conditionals with polymorphism

IMHO you are having trouble applying the video because he isn't really talking about isolated switch statements. In the case of an isolated switch statement, OO merely replaces one sort of switch statement with another. The only way you can get rid of the switch is to replace it with a object belonging to a dynamically chosen class. But how are you going to select the class? Of course with another switch statement! (or other conditional logic)

Generally replacement of switch statements with classes only buys you something if you have a similar switch statement in more than one place. This can happen if

In either of these cases OO lets you reuse the decision that lead to class selection over and over without having to make the actual decision over and over.

In the video his first example (nodes of a parse tree) is of type A - repeated use of the same switch statement. Even though you need a switch statement to assign each node to a class, once you have done so, you can act as if each node in the tree is essentially the same object and avoid messy switch statements whenever you visit a node. All you have to do is call its evaluate(...) method.

The second example in the video - the Update class - is an example of type B - more than one action dependent on type. In the case of the Update class we have the execute(...) and render(...) methods.

That being said, this is what I would do to convert your code:

  1. create a base class with a single method, lets say "frobnicate"
  2. implement the "frobnicate" method of the base class with your default case of the switch statement
  3. for each non-default case in the switch statement, create a subclass
  4. implement the frobnicate method of the subclass with the statements belonging to each non-default case.

To replace the switch statement, I would use three lines:

my $sClass = derive_class($foo); my $oWhatWasOnceASwitchStatementCase = $sClass->new(); $oWhatWasOnceASwitchStatementCase->frobnicate();

The full code looks something like this. To keep it short I've reduced the number of special cases from A,B,C,D to just A,B. I've also set "$foo" from the command line so you can experiment a bit with how different values of "$foo" might behave.

use strict; use warnings; #pretend command line is indirect user input my $foo = \@ARGV; #indirect user input #this replaces your switch statement # use derive_class($foo) to select the class # use frobinate() to replace the action for each if statement branch my $sClass = derive_class($foo); my $oWhatWasOnceASwitchStatementCase = $sClass->new(); $oWhatWasOnceASwitchStatementCase->frobnicate(); #dummy implementation of derive_class($foo) #converts command line arguments to a class sub derive_class { my ($sClass) = $foo->[0]; $sClass = 'Demo::Base' unless $sClass =~ /^Demo::[AB]$/; return $sClass; } #here are your class definitions #implement default case { package Demo::Base; sub new { my ($sClass) = @_; my $self = {}; return bless($self, $sClass); } sub frobnicate { my ($self) = @_; #do similar_to_a print "I'm defaulting to something similar to A\n"; } } #implement when A { package Demo::A; use base 'Demo::Base'; sub frobnicate { my ($self) = @_; #do A print "I'm doing A\n"; } } #implement when B { package Demo::B; use base 'Demo::Base'; sub frobnicate { my ($self) = @_; #do B print "I'm doing B\n"; } }

Best, beth

Update: various edits to improve clarity.

Replies are listed 'Best First'.
Re^2: replace conditionals with polymorphism
by doom (Deacon) on Feb 09, 2009 at 23:24 UTC

    The only way you can get rid of the switch is to replace it with a object belonging to a dynamically chosen class. But how are you going to select the class? Of course with another switch statement (or other conditional logic)!
    Or with a naming convention, right? But then you can do that with a dispatch table as well.

    I think that the main thing that OOP polymorphism gains you is that it's a kind of plug-in architecture -- you can add handling for new cases by adding a new module, without changing the existing ones.

      A dynamically built dispatch table also offers the ability to add handling for new cases without changing the existing ones. And it has the benefits that it is simpler to do, and doesn't push you to spread your logic across multiple files.

      As ELISHEVA said, the big win with OO is that it gives you a framework to dispatch multiple related decisions.

        A dynamically built dispatch table also offers the ability to add handling for new cases without changing the existing ones. And it has the benefits that it is simpler to do, and doesn't push you to spread your logic across multiple files.

        Okay, cool... but I'm not quite seeing how you would set that up. So let's say you have a config file that lists all the allowed cases. Wouldn't you also need to add additional code to handle additional cases, and wouldn't that imply using "multiple files"?