조심스럽게 상속을 쓰고 우선 합성을 고려하라.

게임 속 전사 캐릭터가 있다고 가정하자, 이 캐릭터는 무기로 검, 도끼, 메이스를 쓸 수 있고 플레이 도중 변경 할 수 있다.
이를 코드로 구현하려면 어떻게 해야 할까?
상속으로 해볼까?
public class Warrior implements Character ( /* 전사 공통 */)
public class SwordWarrior extends Warrior { ... }
public class AxWarrior extends Warrior { ... }
public class MaceWarrior extends Warrior { ... }
문제 1. 정체성이 끊긴다.
자바는 객체의 클래스를 런타임에 바꿀 수 없다. 무기를 도끼로 바꾸려면 new AxWarrior()를 새로 만들고 내부 데이터를 옮겨야 한다. 같은 캐릭터가 다른 객체가 된다.
문제 2. 직교하는 축이 늘면 클래스가 곱셈으로 폭발한다.
왼손 장비가 추가된다고 생각해보자. SwordShieldWarrior, SwordSwordWarrior, SwordAxWarrior 등 클래스가 폭발적으로 늘어난다. 다중 상속도 불가능해서 확장에 어려움도 있다.
상속의 함정
- 취약한 기반 클래스 문제
- 부모를 고치면 자식들에 영향이 간다. (Warrior를 위해서 Character를 수정하면 이를 상속 받는 Wizard, Archer 같은 클래스에 영향이 갈 수 있다.)
- 다중 상속 불가능
- 확장에 어려움이 생긴다.
- 결합도 높음
- 부모의 모든 protected 메서드를 자식이 알아야 한다.
합성을 써볼까?
public interface Weapon {
int damage(); // 데미지
int atkSpeed(); // 공격 속도
}
public final class Sword implements Weapon {
public int damage() { return 10; }
public int atkSpeed() { return 20; }
}
public final class Ax implements Weapon {
public int damage() { return 20; }
public int atkSpeed() { return 5; }
}
public final class Mace implements Weapon {
public int damage() { return 15; }
public int atkSpeed() { return 12; }
}
public class Warrior implements Character {
private Weapon weapon; // 합성: 가진다
public Warrior(Weapon weapon) {
this.weapon = weapon;
}
public void changeWeapon(Weapon weapon) {
this.weapon = weapon;
}
@Override
public void attack(Target target) {
// 들고 있는 무기로 공격
}
}
위와 같이 설계하면
Warrior warriorCharacter = new Warrior(new Sword());
warriorCharacter.changeWeapon(new Ax()); // 런타임에 교체
위와 같이 무기를 바꿀 수 있다.
상속 vs 합성
is-a vs has-a 판별표
| 질문 | YES | NO |
| "X는 Y이다"가 자연스러운가? | 상속 후보 | 합성 |
| Y의 모든 행동이 X에 어울리는가? | 상속 후보 | 합성 |
| 런타임에 X의 종류가 바뀔 수 있는가? | 합성 (상속 불가) | 상속도 가능 |
'Java > 객체 지향' 카테고리의 다른 글
| SOLID 원칙 (0) | 2026.07.14 |
|---|---|
| 정적 팩토리 메서드 (0) | 2026.06.15 |
| 방어적 복사 (0) | 2026.06.15 |
| 값 객체(Value Object)와 불변성 (0) | 2026.06.12 |
| 의존성 주입(Dependency Injection)과 조립자 (0) | 2026.06.12 |