조건문을 다형성으로 바꾸기
더 많은 작업
조건문을 다형성으로 바꾸기(Replace Conditional with Polymorphism)는 객체의 타입이나 종류 코드에 따라 동작을 고르는 if-else·switch 분기를, 종류마다 하위 클래스를 두고 각 하위 클래스가 같은 메서드를 오버라이딩하게 바꾸는 리팩토링 기법이다.
마틴 파울러(Martin Fowler)의 리팩토링 카탈로그에 실린 기법이다. 카탈로그의 예는 새 종류(bird.type)에 따라 깃털 상태를 돌려주는 switch 문을, EuropeanSwallow·AfricanSwallow·NorwegianBlueParrot 클래스가 각자 plumage 를 구현하는 형태로 바꾼다.[1]
같은 타입 검사 분기가 여러 메서드에 흩어져 있으면 종류를 하나 더할 때마다 그 분기들을 모두 찾아 고쳐야 한다. 분기를 하위 클래스로 옮기면 새 종류는 새 하위 클래스 하나를 더하는 것으로 끝나고 기존 코드는 고치지 않아도 된다. 그래서 이 기법은 개방-폐쇄 원칙(OCP)을 지키게 해 준다.[2]
- 분기의 기준이 되는 종류마다 하위 클래스를 만든다. 상위 클래스가 아직 없으면 먼저 만들고, 객체를 만드는 곳은 팩토리로 모은다
- 조건문이 들어 있는 메서드를 상위 클래스에 남겨 두고, 한 분기씩 해당 하위 클래스의 오버라이딩 메서드로 옮긴다
- 분기를 옮길 때마다 테스트를 돌려 동작이 같은지 확인한다
- 모든 분기를 옮기면 상위 클래스의 메서드는 추상 메서드로 바꾸거나 기본 동작만 남긴다
바꾸기 전에는 상위 클래스 Player 의 stop() 이 종류 코드를 검사한다.
abstract class Player {
abstract void play();
void stop() {
if (_type == VIDEO) { /* 비디오 정지 */ }
else if (_type == MUSIC) { /* 음악 정지 */ }
else { error(); }
}
}
바꾼 뒤에는 VideoPlayer 와 MusicPlayer 가 각자 stop() 을 오버라이딩하고, 상위 클래스의 분기는 사라진다.
abstract class Player { abstract void play(); abstract void stop(); }
class VideoPlayer extends Player { void play() {...} void stop() { /* 비디오 정지 */ } }
class MusicPlayer extends Player { void play() {...} void stop() { /* 음악 정지 */ } }
호출하는 쪽은 player.stop() 만 부르고, 실제로 어떤 stop() 이 실행될지는 객체의 실제 타입이 정한다(동적 바인딩).
| 기법 | 하는 일 | 조건 분기와의 관계 |
|---|---|---|
| 조건문을 다형성으로 바꾸기 | 타입별 분기를 하위 클래스의 오버라이딩으로 옮긴다 | 분기 자체를 없앤다 |
| 메서드 인라인(Inline Method, Inline Function) | 본문이 이름만큼 명확한 작은 메서드를 호출하는 곳에 풀어 넣고 메서드를 지운다. 메서드 추출의 반대 | 분기와 무관 |
| 다운캐스트 캡슐화(Encapsulate Downcast) | 호출하는 쪽마다 하던 다운캐스트를 메서드 안으로 옮겨 구체 타입을 돌려준다(파울러 1판) | 타입 검사를 없애지 않는다 |
| 생성자를 팩토리 메서드로 바꾸기(Replace Constructor with Factory Method) | new 호출을 팩토리 메서드로 감싸 어느 하위 클래스를 만들지 한곳에서 고른다 | 생성 시점의 분기를 모을 뿐 동작 분기는 남는다 |
| 조건문 분해(Decompose Conditional) | 복잡한 조건식과 각 분기 본문을 메서드로 추출한다 | 분기는 그대로 남는다 |
조건문을 다형성으로 바꿀 때 객체 생성 부분에는 생성자를 팩토리 메서드로 바꾸기를 함께 쓰는 경우가 많다. 그러나 동작 분기를 하위 클래스의 메서드로 옮기는 것은 조건문을 다형성으로 바꾸기이다.
- 분기가 한 곳뿐이고 종류가 늘어날 일이 없으면 하위 클래스를 만드는 비용이 더 크다
- 분기 기준이 객체의 종류가 아니라 실행 중 바뀌는 값(금액 구간, 날짜)이면 상태 패턴이나 전략 객체가 더 맞다
- ↑ Martin Fowler, 「Replace Conditional with Polymorphism」, Refactoring Catalog, https://refactoring.com/catalog/replaceConditionalWithPolymorphism.html, 확인일: 2026-11-04.
- ↑ 「Replace Conditional with Polymorphism」, Refactoring.Guru, https://refactoring.guru/replace-conditional-with-polymorphism, 확인일: 2026-11-04.