Beware type switches

From CSSEMediaWiki
(Difference between revisions)
Jump to: navigation, search
(Last few edits for brief initial description)
Line 4: Line 4:
  
 
A possible solution is to replace any type code with a type class or Strategy pattern. See [[Martin Fowler]]'s example at [[http://www.refactoring.com/catalog/replaceTypeCodeWithStateStrategy.html Replace Type Code With State/Strategy]]
 
A possible solution is to replace any type code with a type class or Strategy pattern. See [[Martin Fowler]]'s example at [[http://www.refactoring.com/catalog/replaceTypeCodeWithStateStrategy.html Replace Type Code With State/Strategy]]
 +
 +
To illustrate imagine the following Player class, who could be of type "Knight", "Wizard" or "Elf"
 +
 +
[[Image:player-class-diagram1.png]]
 +
 +
The attack() method might operate as follows:
 +
 +
void attack(Creature creature) {
 +
 +
  if(type.equals("Knight")) {
 +
    int damage = this.attackStrength - creature.toughness;
 +
    creature.lowerHealth(damage);
 +
 +
  } else if (type.equals("Wizard")) {
 +
    int damage = this.attackStrength - creature.resilience;
 +
    creature.lowerHealth(damage);
 +
 +
  } else //must be Elf
 +
    int damage = this.attackStrength - creature.armour;
 +
    creature.lowerHealth(damage);
 +
  }
 +
}
 +
 +
Obviously this is bad from a maintenance point of view as every time a new Player type is added, the attack method needs to be changed. In a big game, this method could quickly become large. If a player type got removed, the appropriate section of this if-elseif-elseif...else block would need to be removed. Also, this does not support players changing weapons (there is no reason an elf couldn't use a sword if they wanted).
 +
 +
A better design would be to subclass Player, and override the (abstract) attack method in each subclass:
 +
 +
[[Image:player-class-diagram2.png]]
 +
 +
This is only one possible solution, and not necessarily the best (still has limited support for dynamically changing weapons). Another (and possibly better) solution is to use a strategy design pattern
 +
 +
 +
  
 
== See also ==
 
== See also ==
 
* [[Switch statements smell]]
 
* [[Switch statements smell]]
 
* [[Riel's heuristics]]
 
* [[Riel's heuristics]]

Revision as of 02:41, 23 July 2008

This is Reil's heuristic #5.12

Type switches involve changing behaviour based on the object's type. Problems occur when multiple switches occur over the same variable in the same class, since when one is modified, all occurrences may need to be changed.

A possible solution is to replace any type code with a type class or Strategy pattern. See Martin Fowler's example at [Replace Type Code With State/Strategy]

To illustrate imagine the following Player class, who could be of type "Knight", "Wizard" or "Elf"

Player-class-diagram1.png

The attack() method might operate as follows:

void attack(Creature creature) {

 if(type.equals("Knight")) {
   int damage = this.attackStrength - creature.toughness;
   creature.lowerHealth(damage);

 } else if (type.equals("Wizard")) {
   int damage = this.attackStrength - creature.resilience;
   creature.lowerHealth(damage);

 } else //must be Elf
   int damage = this.attackStrength - creature.armour;
   creature.lowerHealth(damage); 
 }
}

Obviously this is bad from a maintenance point of view as every time a new Player type is added, the attack method needs to be changed. In a big game, this method could quickly become large. If a player type got removed, the appropriate section of this if-elseif-elseif...else block would need to be removed. Also, this does not support players changing weapons (there is no reason an elf couldn't use a sword if they wanted).

A better design would be to subclass Player, and override the (abstract) attack method in each subclass:

Player-class-diagram2.png

This is only one possible solution, and not necessarily the best (still has limited support for dynamically changing weapons). Another (and possibly better) solution is to use a strategy design pattern



See also

Personal tools