켄트 벡의 테스트 주도 개발 팩토리 메서드
책에서 팩토리 메서드 패턴을 다룰 때, 구체적인 예제 코드를 통해 TDD 프로세스를 기반으로 설계를 발전시키는 과정을 보여준다. 특정 장마다 코드가 점진적으로 진화하며, 30장은 디자인 패턴을 TDD로 리팩토링하는 데 초점을 맞추기 때문에 팩토리 메서드가 명시적으로 언급된다고 해서 완성된 하나의 코드 블록이 바로 제시되지는 않는다. 대신, 책의 맥락에서 Money
예제를 기반으로 팩토리 메서드가 어떻게 도입되는지를 단계적으로 설명한다.
아래에서는 책의 Money
예제를 기반으로 팩토리 메서드가 적용되기 전과 후의 코드를 상세히 분석하고, TDD 과정에서 어떻게 발전하는지 설명해 보겠다.
책에서의 초기 코드 (팩토리 메서드 도입 전)
책의 초반에서는 Money
클래스를 다루며 통화와 금액을 표현하는 예제를 사용한다. 초기에는 아래 코드와 같이 Dollar
와 Franc
같은 구체적인 클래스를 직접 생성한다.
class MoneyTest {
public void testMultiplication() {
Dollar five = new Dollar(5);
Dollar product = five.times(2);
assertEquals(10, product.amount);
}
public void testFrancMultiplication() {
Franc five = new Franc(5);
Franc product = five.times(2);
assertEquals(10, product.amount);
}
}
class Dollar {
int amount;
Dollar(int amount) {
this.amount = amount;
}
Dollar times(int multiplier) {
return new Dollar(amount * multiplier);
}
}
class Franc {
int amount;
Franc(int amount) {
this.amount = amount;
}
Franc times(int multiplier) {
return new Franc(amount * multiplier);
}
}
초기 코드의 문제점
- 중복:
Dollar
와Franc
는 구조적으로 비슷하지만 별도의 클래스다.times
메서드 로직이 중복된다. - 클라이언트 의존성: 테스트 코드에서
Dollar
와Franc
를 직접 생성하므로, 구체적인 클래스에 의존한다. - 확장성 부족: 새로운 통화(예: 유로)를 추가하려면 또 다른 클래스를 만들고 테스트를 반복해야 한다.
켄트 벡은 이런 문제를 TDD로 해결하며 점진적으로 리팩토링한다.
리팩토링 1단계: 공통 인터페이스 도입
책에서는 중복을 줄이기 위해 Money
라는 공통 상위 클래스나 인터페이스를 도입한다. 이는 팩토리 메서드의 전 단계로, 객체 생성을 통합할 기반을 마련한다. 리팩토링된 코드는 다음과 같다:
abstract class Money {
protected int amount;
abstract Money times(int multiplier);
public boolean equals(Object object) {
Money money = (Money) object;
return amount == money.amount && getClass() == money.getClass();
}
}
class Dollar extends Money {
Dollar(int amount) {
this.amount = amount;
}
Money times(int multiplier) {
return new Dollar(amount * multiplier);
}
}
class Franc extends Money {
Franc(int amount) {
this.amount = amount;
}
Money times(int multiplier) {
return new Franc(amount * multiplier);
}
}
class MoneyTest {
public void testMultiplication() {
Money five = new Dollar(5);
Money product = five.times(2);
assertEquals(10, product.amount);
}
public void testFrancMultiplication() {
Money five = new Franc(5);
Money product = five.times(2);
assertEquals(10, product.amount);
}
}
변화
Money
추상 클래스를 도입해 공통 로직(equals
)을 상위로 이동.times
메서드는 여전히 하위 클래스에서 구현되지만, 반환 타입이Money
로 통일됨.
여전히 테스트 코드에서 new Dollar()
와 new Franc()
를 직접 호출하므로 구체 클래스에 의존성이 남아 있다.
팩토리 메서드 도입 (책의 30장 맥락)
30장에서 디자인 패턴을 다루며, 켄트 벡은 팩토리 메서드를 통해 객체 생성을 캡슐화하는 방법을 제안한다. 이는 클라이언트(테스트 코드)가 구체적인 클래스(Dollar
, Franc
)를 직접 생성하지 않도록 하고, 생성 로직을 별도로 분리한다.
abstract class Money {
protected int amount;
protected String currency;
Money(int amount, String currency) {
this.amount = amount;
this.currency = currency;
}
abstract Money times(int multiplier);
static Money dollar(int amount) {
return new Dollar(amount, "USD");
}
static Money franc(int amount) {
return new Franc(amount, "CHF");
}
String currency() {
return currency;
}
}
class Dollar extends Money {
Dollar(int amount, String currency) {
super(amount, currency);
}
Money times(int multiplier) {
return new Dollar(amount * multiplier, currency);
}
}
class Franc extends Money {
Franc(int amount, String currency) {
super(amount, currency);
}
Money times(int multiplier) {
return new Franc(amount * multiplier, currency);
}
}
class MoneyTest {
public void testMultiplication() {
Money five = Money.dollar(5);
Money product = five.times(2);
assertEquals(10, product.amount);
}
public void testFrancMultiplication() {
Money five = Money.franc(5);
Money product = five.times(2);
assertEquals(10, product.amount);
}
}
팩토리 메서드의 도입
Money
클래스에 정적 팩토리 메서드(dollar
,franc
)를 추가.- 클라이언트는
new Dollar()
대신Money.dollar()
를 호출하며, 구체적인 클래스 생성이 캡슐화됨. currency
속성을 추가해 통화 정보를 명시적으로 관리.
이것이 책에서 팩토리 메서드의 첫 번째 형태로 나타날 수 있는 모습이다. 켄트 벡은 TDD에서 "가장 단순한 것"을 먼저 구현한 뒤 필요에 따라 개선하므로, 정적 팩토리 메서드가 초기 단계에서 적합하다.
결론
켄트 벡의 테스트 주도 개발 30장에서 팩토리 메서드는 Money
예제를 통해 점진적으로 도입된다. 초기에는 중복 제거와 추상화를 위해 정적 팩토리 메서드가 사용되고, 이후 디자인 패턴의 정식 형태로 별도의 팩토리 클래스가 추가된다. 책의 코드는 테스트 주도로 발전하며, 클라이언트 코드의 결합도를 낮추고 확장성을 높이는 데 초점을 맞춘다.
'항해99 플러스 > 사전스터디' 카테고리의 다른 글
[TDD] Kent Beck - 테스트 주도 개발 (0) | 2025.03.11 |
---|---|
[TDD방법론 사전스터디] 2주차 (2) | 2024.09.03 |
[Java 스터디] 강의 3주차 (1) | 2024.09.03 |
[TDD방법론 사전스터디] 1주차 (4) | 2024.08.26 |
[Java 스터디] 강의 2주차 (0) | 2024.08.21 |