Created
July 26, 2025 11:37
-
-
Save xpmatteo/9d54357190cbceb6b51c201e935a8b3f to your computer and use it in GitHub Desktop.
RPG Combat Kata - Polymorphic Refactoring to Eliminate IF Statements
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ABOUTME: Represents a living RPG character with full capabilities | |
// ABOUTME: Handles damage reception, healing, and state transitions to dead when health reaches zero | |
public class AliveCharacter extends RPGCharacterBase { | |
public AliveCharacter() { | |
super(MAX_H); | |
} | |
public AliveCharacter(int health) { | |
super(Math.max(0, Math.min(health, MAX_H))); | |
} | |
@Override | |
public boolean isAlive() { | |
return true; | |
} | |
@Override | |
public RPGCharacterBase heal(int hp) { | |
int newHealth = Math.min(health + hp, MAX_H); | |
return new AliveCharacter(newHealth); | |
} | |
@Override | |
protected RPGCharacterBase receiveDamage(RPGCharacterBase attacker, int damage) { | |
if (attacker != this) { | |
int newHealth = Math.max(health - damage, 0); | |
if (newHealth == 0) { | |
return new DeadCharacter(); | |
} | |
return new AliveCharacter(newHealth); | |
} | |
return this; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ABOUTME: Represents a dead RPG character with limited capabilities | |
// ABOUTME: Cannot heal or change state, but can still receive damage without effect | |
public class DeadCharacter extends RPGCharacterBase { | |
public DeadCharacter() { | |
super(0); | |
} | |
@Override | |
public boolean isAlive() { | |
return false; | |
} | |
@Override | |
public RPGCharacterBase heal(int hp) { | |
return this; | |
} | |
@Override | |
protected RPGCharacterBase receiveDamage(RPGCharacterBase attacker, int damage) { | |
return this; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ABOUTME: Facade class that maintains API compatibility with original RPGCharacter | |
// ABOUTME: Delegates to polymorphic implementation while preserving mutable interface | |
public class RPGCharacter { | |
public static final int MAX_H = 1000; | |
private RPGCharacterBase delegate; | |
public RPGCharacter() { | |
this.delegate = RPGCharacterFactory.createNewCharacter(); | |
} | |
public boolean isAlive() { | |
return delegate.isAlive(); | |
} | |
public boolean isDead() { | |
return delegate.isDead(); | |
} | |
public void dealDamage(RPGCharacter victim, int damage) { | |
victim.delegate = this.delegate.dealDamage(victim.delegate, damage); | |
} | |
public int health() { | |
return delegate.health(); | |
} | |
public void heal(int hp) { | |
delegate = delegate.heal(hp); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ABOUTME: Abstract base class for RPG characters with shared behavior | |
// ABOUTME: Provides common interface and delegates state-specific behavior to subclasses | |
public abstract class RPGCharacterBase { | |
public static final int MAX_H = 1000; | |
protected int health; | |
protected RPGCharacterBase(int health) { | |
this.health = health; | |
} | |
public int health() { | |
return health; | |
} | |
public abstract boolean isAlive(); | |
public boolean isDead() { | |
return !isAlive(); | |
} | |
public abstract RPGCharacterBase heal(int hp); | |
public RPGCharacterBase dealDamage(RPGCharacterBase victim, int damage) { | |
return victim.receiveDamage(this, damage); | |
} | |
protected abstract RPGCharacterBase receiveDamage(RPGCharacterBase attacker, int damage); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ABOUTME: Factory for creating properly configured RPG characters | |
// ABOUTME: Encapsulates character creation logic and provides convenient factory methods | |
public class RPGCharacterFactory { | |
public static RPGCharacterBase createNewCharacter() { | |
return new AliveCharacter(); | |
} | |
public static RPGCharacterBase createCharacterWithHealth(int health) { | |
if (health > 0) { | |
return new AliveCharacter(health); | |
} else { | |
return new DeadCharacter(); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment