7장 사과와 오렌지
Franc 과 Dollar 비교하기 |
@Test
public void testEquality() {
assertTrue(new Dollar(5).equals(new Dollar(5)));
assertFalse(new Dollar(5).equals(new Dollar(6)));
assertTrue(new Franc(5).equals(new Franc(5)));
assertFalse(new Franc(5).equals(new Franc(6)));
assertFalse(new Franc(5).equals(new Dollar(5)));
}
실패한다.
클래스의 금액과 클래스를 같이 체크해 주자.
public boolean equals(Object object) {
Money money = (Money) object;
return amount == money.amount
&& getClass().equals(money.getClass());
}
이제 공통 times() 코드를 처리하자. 혼합된 통화간의 연산에 대해 다루어야 한다.
- 결함을 끄집어내 테스트에 담음
- getClass() 로 테스트를 통과하게 만듬.
- 자바 객체의 용어를 사용하는것보다 재정분야에 맞는 용어를 사용하고 싶지만 미룸.
8장 객체 만들기 Makin' Object
두 times( ) 구현코드가 거의 같으므로 양쪽 모두 Money를 반환하게 만들자.
Franc
Money times(int multiplier){
return new Franc(amount*multiplier);
}
Dollar
Money times(int multiplier){
return new Dollar(amount*multiplier);
}
하위클래스에 대한 직접 참조를 적게 하려면,
Money에 Dollar를 반환하는 factory method 도입하자.
@Test
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에 대한 참조를 없애기 위해 테스트 선언부를 바꿈.
@Test
public void testMultiplication() {
Money five = Money.dollar(5);
assertEquals(new Dollar(10), five.times(2));
assertEquals(new Dollar(15), five.times(3));
}
아직 times() 구현이 안되기 때문에
Money 를 추상 클래스로 변경한 후 Money.times()를 선언
Money
abstract class Money {
abstract Money times(int multiplier);
static Money dollar(int amount) {
return new Dollar(amount);
}
...
}
이제 팩토리 메서드를 나머지 모든 곳에서 사용가능.
@Test
public void testEquality() {
assertTrue(Money.dollar(5).equals(Money.dollar(5)));
assertFalse(Money.dollar(5).equals(Money.dollar(6)));
assertTrue(new Franc(5).equals(new Franc(5)));
assertFalse(new Franc(5).equals(new Franc(6)));
assertFalse(new Franc(5).equals(Money.dollar(5)));
}
하위클래스의 존재를 테스트에서 분리하게 되면서, 상속구조를 변경 가능하게 되었다.
Money.franc() 도 똑같이 구현하자
- 동일한 메서드(times)의 메서드 서명부 통일
- 메서드 선언부를 공통 상위 클래스로 옮김.
- 팩토리 메서드를 도입하여 테스트 코드에서 콘크리트 하위 클래스 분리
- 하위클래스가 사라져 어떤 테스트는 불필요한 여분의 것이 된다는 것을 인식했지만, 그냥 둠.
9장 우리가 사는 시간 TIMES WE’RE LIVIN’ IN
불필요한 하위 클래스를 제거하는데 도움이 되는 항목이 무엇일까?
통화 개념 도입?
$5 + 10CHF = $10(환율이 2:1일 경우)
Money 반올림?
hashCode() Equal null Equal object
Dollar/Franc 중복
공용 times
통화? testFrancMultiplication 제거 |
통화를 표현하기 위한 복잡한 객체,
그 객체들이 필요한 만큼만 만들어지도록 하는 경량 팩토리 flyweight factories 를 사용하면 좋겠다.
하지만 당분간 문자열로 대신하자.
Money 에 currency() 메서드를 선언하고 두 하위 클래스에서 구현
통화를 인스턴스 변수에 저장하고, 메서드에서 그냥 반환하게 하자.
Franc
private String currency;
public Franc(int amount) {
this.amount = amount;
this.currency = "CHF";
}
String currency() {
return currency;
}
Dollar 도 똑같이 변경.
이제 변수와 currency() 가 동일하므로 위로 올리자.
Money
protected String currency;
String currency() {
return currency;
}
문자열을 정적 팩토리 메소드에 옮겨 생성자를 동일하게 만듦.
생성자를 호출하는 코드 고쳐줌.
이제 Franc의 times() 정리
Money 팩토리 메서드 가 문자열을 전달
Franc 생성자에 인스턴스 변수 할당.
Dolloar 도 동일하게 구현
Money
static Money dollar(int amount) {
return new Dollar(amount, "USD");
}
Dollar
public Dollar(int amount, String currency) {
this.amount = amount;
this.currency = currency;
}
Money times(int multiplier){
return Money.dollar(amount*multiplier);
}
이제 두 생성자가 동일해 졌으니 상위클래스로 올리자.
Money
public Money(int amount, String currency) {
this.amount = amount;
this.currency = currency;
}
Franc
public Franc(int amount, String currency) {
super(amount, currency);
}
Dollar
public Dollar(int amount, String currency) {
super(amount, currency);
}
- 큰 설계 전에 더 작은 작업을 수행했다.
- 다른 부분을 팩토리메서드(호출자)로 옮겨서 두 생성자를 일치시켰다
- times()가 팩토리 메서드를 사용하도록 리팩토링은 잠시 중단
- 비슷한 리팩토링을 한번의 큰단계로 진행
- 동일한 생성자들을 상위클래스로 옮김
'IT Book Summary > TDD' 카테고리의 다른 글
18장-20장 xUnit (0) | 2020.03.24 |
---|---|
13-17장 (0) | 2020.03.18 |
10-12장 (0) | 2020.03.10 |
4-6장 (0) | 2020.03.02 |
1-3장 (0) | 2020.02.25 |