Java from Basics to Mastery — Part 4
Using polymorphism with inheritance and interfaces
The articles written on this blog were created with the goal of teaching. Also, the information in the article may be incorrect, so please be careful.
Interfaces and inheritance can be used when multiple objects need to be used in the same way. The calling code is more resistant to change if it relies on the necessary role rather than a specific class.
interface
public interface Damageable {
boolean isAlive();
void takeDamage(int amount);
}
public final class Monster implements Damageable {
private int health = 100;
@Override
public boolean isAlive() {
return health > 0;
}
@Override
public void takeDamage(int amount) {
health = Math.max(0, health - amount);
}
}
The attack code is Damageable, not Monster. Even if you add a destructible box later, it can be handled with the same contract.
Abstract classes and inheritance
public abstract class Skill {
private final String name;
protected Skill(String name) {
this.name = name;
}
public String getName() {
return name;
}
public abstract void execute(Damageable target);
}
Abstract classes can share common state and implementation while leaving some behavior to their children. Inheritance also combines the rules of the parent, so if you make it deeper for simple code reuse, the scope of change increases.
polymorphism
List<Damageable> targets = List.of(
new Monster(),
new TrainingDummy()
);
for (Damageable target : targets) {
target.takeDamage(10);
}
Even if the same call is made, the implementation appropriate for the actual object is executed. The caller does not have to list all concrete types with instanceof.
Interfaces express roles and abstract classes provide a common foundation. If you can combine small, composable objects, it is often simpler than inheritance.