by 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.