Java 기초부터 마스터까지 — 4화
상속과 인터페이스로 다형성 사용하기
본 블로그 작성 글들은, 강의를 목표로 하고 제작되었습니다. 또한 작성된 글의 정보도 틀렸을 수 있으니, 주의해주세요.
여러 객체가 같은 방식으로 사용되어야 할 때 인터페이스와 상속을 이용할 수 있다. 호출하는 코드는 구체적인 클래스보다 필요한 역할에 의존하는 편이 변경에 강하다.
인터페이스
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);
}
}
공격 코드는 Monster가 아니라 Damageable을 받으면 된다. 나중에 파괴 가능한 상자를 추가해도 같은 계약으로 처리할 수 있다.
추상 클래스와 상속
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);
}
추상 클래스는 공통 상태와 구현을 공유하면서 일부 동작을 자식에게 맡길 수 있다. 상속은 부모의 규칙까지 결합하므로 단순한 코드 재사용만을 위해 깊게 만들면 변경 범위가 커진다.
다형성
List<Damageable> targets = List.of(
new Monster(),
new TrainingDummy()
);
for (Damageable target : targets) {
target.takeDamage(10);
}
같은 호출을 해도 실제 객체에 맞는 구현이 실행된다. 호출자는 instanceof로 모든 구체 타입을 나열하지 않아도 된다.
인터페이스는 역할을 표현하고 추상 클래스는 공통 기반을 제공한다. 구성이 가능한 작은 객체를 조합할 수 있다면 상속보다 그 방법이 더 단순한 경우도 많다.