본문 바로가기

책읽기/TDD:ByExample

TDD_8

13장 진짜로 만들기

<할일>

$5 + 10CHF = $10 (1:2의 환율일 경우)
$5 + $5 = $10

 

지금까지 $5 + $5 = $10을 해결하고 있었다.

하지만 코드에 중복이 있기에 완료표시를 할 수 없다.

 

현재 Bank클래스로 만든 bank인스턴스의 메소드 reduce는 amount가 10인 Money형 객체를 반환하고 있다.

이와 테스트코드의 five.plus(five)는 중복코드라고 볼 수 있다.

 reduce메소드에서 적절한 Money객체를 반환하도록 해야 한다.

 

<할일>

$5 + 10CHF = $10 (1:2의 환율일 경우)
$5 + $5 = $10
$5 + $5에서 Money반환하기

 우리의 코드를 잘 보면 plus메소드는 Money객체를 생성시켜서 Expression형으로 반환한다.

따라서 plus는 Expression을 반환해야 한다.

이 말은 두 화폐의 합은 sum이 되야 한다는 말과 같다.

 

 

위의 가정에 따라 새 테스트를 작성했다.

plus의 결과가 Expression의 Sum인가를 확인하기 위해서다.

augend는 연산자의 앞(피가산수)이고 addend는 피연산자중 뒤 숫자이다.

 

이제 코드의 컴파일에러를 잡아야 한다.

책을 어느정도 읽었으니 뭘 할 지 생각해봤다.

1. Sum클래스를 만든다.

2. Money의 plus가 만든 Sum클래스형을 반환한다.

3. Sum클래스는 생성자로 초기화 하도록 한다.

4. Sum클래스는 Expression인터페이스를 구현해야 할 것이다.

 

 

Sum클래스는 피연산자가 되는 두 객체를 정의하는 클래스로 처음 만들 것이다.

 

클래스 생성
plus가 Sum을 반환하도록
두합은 Expression형이므로 인터페이스를 구현하는 클래스로 만듦

컴파일이 된다.

하지만 테스트는 실패한다. 

Sum 클래스의 생성자를 비워뒀기 때문.

 

 

생성자를 채워 주었고 테스트가 성공한다.

 

 

이제 Bank.reduce()는 Sum을 전달받는다.

만약 Sum이 가진 addend와 augend의 통화가 동일하고,
reduce로 얻어내고자 하는 통화 역시 같다면,

결과는 Sum 내에 있는 Money들의 amount를 합친 것과 같은 통화의 Money객체여야 한다.

이 가정을 테스트로 옮겨보자.

하드코딩한 reduce함수를 고쳐야 한다.

이 reduce함수는 두가지 이유로 지저분하다.

1. 캐스팅 - 이 코드는 sum 뿐만 아니라 모든 Expression에 대해 작동해야 한다.

2. public형 필드와 그 필드들에 대한 두 단계에 걸친 레퍼런스.(amount)

 

바로 고친다.

 

 

 

reduce의 과정에서 Bank가 들어가서 환율에 대한 무언가를 해줘야 할 것 같다.

이 것은 간단한 리펙토링이기 때문에 나중을 위해 놔 두도록 한다.

 

이 과정까지 완료하면 테스트가 성공하고 있을 것이다.

 

 

 

 

 

현재 흐름은,

화폐를 생성 -> plus로 더한 값을 Expression(sum)으로 반환 -> Expression(sum)을 Bank의 reduce로 환율계산 요청

-> Bank의 reduce는 Sum의 reduce에서 amount를 합한 새로운 Money객체를 얻어와서 반환.

 

 

만약 reduce가 sum값을 받지 않고 Money를 받는다면 어떨까?

<할일>

$5 + 10CHF = $10 (1:2의 환율일 경우)
$5 + $5 = $10
$5 + $5에서 Money반환하기
Bank.reduce(Money)

바로 해결하기 위하여

새로운 테스트를 작성한다.

 

result를 구할 때, bank.reduce()의 매개변수로 "USD"가 추가되어야 한다.

instanceof를 이용하여 Expression형이 아닌 Money형이 들어오면 source를 Money로 캐스팅하여 반환하게 분기처리하였다.

 

instanceof와 상속을 알고싶다면, 

lbmmbl.tistory.com/29

 

[JAVA] 15.업캐스팅, 다운캐스팅, instanceof

안녕하세요 IT뽀로로입니다. 오늘은 자바의 캐스팅에 대하여 알아보도록 할 텐데요. 캐스팅은 업 캐스팅과 다운 캐스팅 두 가지가 있습니다. #업 캐스팅(Upcasting) 서브 클래스는 슈퍼 클래스의 모

lbmmbl.tistory.com

 

 

여전히 초록막대 상태이다. 

하지만 지저분하므로 리펙토링하자.

 

클래스를 명시적으로 검사하는 코드(instancof) 가 있을 때에는, 항상 다형성을 사용하도록 바꾸는 것이 좋다.

현재 Expression을 구현하는 클래스는 Money와 Sum.

Sum의 reduce를 Money에도 구현한다면, reduce()를 Expression인터페이스에도 추가할 수 있다.

 

 

 

Money의 reduce가 Money의 인스턴스이면 Money형으로 바꾸어 반환하던 것을,

Money형의 reduce()를 통해 객체를 반환한다는 의미로 코드를 작성한다.

 

 

Money에도 reduce()를 구현한다.

Money객체 자신을 반환한다.

 

이제 공통이 된 reduce()를 인터페이스에 등록한다.

 

그럼 이제 캐스팅과 클래스 검사 코드를 제거할 수 있다.

 

 

이제 reduce()에

Expression sum이 매개변수로 들어오면, Bank의 reduce가 실행 될 것이고,

Money객체가 들어오면 Money의 reduce가 실행된다.

다형성을 이용하여 리펙토링을 한 것이다.

 

 

자바에서는 이 위치매개변수의 다름만으로 두 클래스의 이름만 같은 메소드가 어떻게 다른지 코드로 담아내기가 쉽지 않다.

(지원하는 언어에서는 Bank.reduce(), Money.reduce()처럼 명백하게 구분하도록 문법적으로 지원해준다고 한다.)

 

 

다음 할 일을 적어놓고 이번 장을 마무리한다.

 

<할일>

$5 + 10CHF = $10 (1:2의 환율일 경우)
$5 + $5 = $10
$5 + $5에서 Money반환하기
//해결//Bank.reduce(Money)
Money에 대한 통화 변환을 수행하는 Reduce
Reduce(Bank, String)

 

 

'책읽기 > TDD:ByExample' 카테고리의 다른 글

점진적인 개선  (0) 2021.01.22
TDD_9  (0) 2020.11.24
TDD_7  (0) 2020.11.17
TDD_6  (0) 2020.11.11
TDD_5  (0) 2020.11.10