Replace conditional with polymorphism


Link to this posting

Postby Ursego » 08 Aug 2019, 11:26

Problem

You have a conditional that performs various actions depending on object type or properties:

Code: Select all
class Bird {
   // ...
   double getSpeed(BirdType birdType) {
      switch (birdType) {
         case BirdType.EUROPEAN:
            return getBaseSpeed();
         case BirdType.AFRICAN:
            return getBaseSpeed() - getLoadFactor() * numberOfCoconuts;
         case BirdType.NORWEGIAN_BLUE:
            return (isNailed) ? 0 : getBaseSpeed(voltage);
      }
      throw new Exception("Invalid bird type " + birdType);
   }
}

Somewhere in calling code:

Code: Select all
europeanBirdSpeed = bird.getSpeed(BirdType.EUROPEAN);
africanBirdSpeed = bird.getSpeed(BirdType.AFRICAN);
norvegianBlueBirdSpeed = bird.getSpeed(BirdType.NORWEGIAN_BLUE);

Solution

Create subclasses matching the branches of the conditional. In them, create a shared method and move code from the corresponding branch of the conditional to it. Then replace the conditional with the relevant method call. The result is that the proper implementation will be attained via polymorphism depending on the object class:

Code: Select all
abstract class Bird {
   // ...
   abstract double getSpeed();
}

class EuropeanBird extends Bird {
   double getSpeed() {
      return getBaseSpeed();
   }
}

class AfricanBird extends Bird {
   double getSpeed() {
      return getBaseSpeed() - getLoadFactor() * numberOfCoconuts;
   }
}

class NorwegianBlueBird extends Bird {
   double getSpeed() {
      return (isNailed) ? 0 : getBaseSpeed(voltage);
   }
}

Somewhere in calling code:

Code: Select all
europeanBirdSpeed = europeanBird.getSpeed();
africanBirdSpeed = africanBird.getSpeed();
norvegianBlueBirdSpeed = norvegianBlueBird.getSpeed();

Benefits

• This technique adheres to the Tell-Don't-Ask principle: instead of asking an object about its state and then performing actions based on this, it's much easier to simply tell the object what it needs to do and let it decide for itself how to do that.

• Removes duplicate code. You get rid of many almost identical conditionals.

• If you need to add a new execution variant, all you need to do is create a new subclass without touching the existing code.
User avatar
Ursego
Site Admin
 
Posts: 143
Joined: 19 Feb 2013, 20:33



Ketones are a more high-octane fuel for your brain than glucose. Become a biohacker and upgrade yourself to version 2.0!



cron
Traffic Counter

eXTReMe Tracker