Test Driven Development
각 단계에는 서로 다른 목적이 있다. 다른 스타일의 해법, 다른 미적 시각을 필요로 한다.
첫 네 단계는 빨리 진행해야 한다. 그러면 새 기능이 포함되더라도 잘 알고 있는 상태에 이를 수 있다.
모든 설계 원칙을 무시하고 빠르게 네 단계를 진행해도 좋다.
다섯 번째 단계 없이는 앞의 네 단계도 제대로 되지 않는다.
// Franc
Franc times(int mulitplier) {
return new Franc(amount * multiplier);
}
// Dollar
Dollar times(int mulitplier) {
return new Dollar(amount * multiplier);
}
Franc.times() 와 Dollar.times()의 메서드는 동일해 보인다.
Money class를 상속받게 해 중복을 제거한다.
그러려면 일단 양쪽 모두 Money를 반환하게 만들면 더 비슷하게 만들 수 있다.
// Franc
Money times(int mulitplier) {
return new Franc(amount * multiplier);
}
// Dollar
Money times(int mulitplier) {
return new Dollar(amount * multiplier);
}
하위 클래스에 대한 직접적인 참조가 적어진다면 하위 클래스를 제거하기 위해 한 발짝 더 다가섰다고 할 수 있다.
Money에 Dollar를 반환하는 팩토리 메서드를 도입한다.
public void testMultiplication() {
Dollar five = Money.dollar(5);
assertEquals(new Dollar(10), five.times(2));
assertEquals(new Dollar(15), five.times(3));
}
// Money
static Dollar dollar(int amount) {
return new Dollar(amount);
}
Dollar에 대한 참조가 사라지길 바라므로 테스트의 선언부를 바꾼다.
public void testMultiplication() {
Money five = Money.dollar(5);
assertEquals(new Dollar(10), five.times(2));
assertEquals(new Dollar(15), five.times(3));
}
Money에는 times()를 정의하지 않았다.
팩토리 메서드를 테스트 코드의 나머지 모든 곳에서 사용할 수 있다.
public void testMultiplication() {
Money five = Money.dollar(5);
assertEquals (Money.dollar(10), five.times(2));
assertEquals (Money.dollar(15), five.times(3));
}
public void testEquality() {
assertTrue(Money.dollar(5).equals(Money.dollar(5)));
assertFalse(Money.dollar(5).equals(Money.dollar(6)));
assertFalse(new Franc(5).equals(Money.dollar(5)));
}
하위 클래스의 존재를 테스트에서 분리함으로써 어떤 모델 코드에도 영향을 주지 않고 상속 구조를 마음대로 변경할 수 있게 됐다.