30 June 2005

Conditionals and polymorphism

I've always had a nagging issue with the refactoring item replace conditional with polymorphism. The concept is that you have a bunch of objects that are acted upon in the same situation but with different underlying actions. With the canonical Shape class and its Circle, Square, and Triangle subclasses, a poor design would have the draw method in Shape and a conditional within that method to draw each possible type. That's a little contrived because of the simplicity of the example, but real-world examples are common resulting from tree-forest syndrome in bulky classes, or from code bloat as more and more classes are added--requiring copy-pastes with small alterations to the conditional.

This refactoring method converts the multiple-line conditional blocks into single lines of code that distribute their work across an already-existing class hierarchy (see below). The problem I have is that, while the superfluous conditionals are removed, there's always one or two that must remain: those that create the separate objects in the first place.

if x then
    process
else if y then
    process
else if z then
    process
end if

Becomes:

base->process() - - - - > calls x or y or z

That "redistribution" is key, and eliminates so much noisy, conditional code that I'm sometimes unjustly suspicious of every conditional I see. This is similar to how the standard's algorithms have made loops suspicious--breaking them up into templates (find<>, for_each<>, set_intersection<>, etc.) and predicates. Absolutes are never so absolute, so there are times to use loops and conditionals (and times when the standard binders justdon'twork). The Boost library and features in updates to the C++ standard and especially some of the functional magic going on in Alexandrescu's techniques are all helpful in this regard.

[ posted by sstrader on 30 June 2005 at 6:29:10 PM in Programming ]