지금까지 환산은 통화가 같아 값이 그대로였다. 이제 진짜 변환을 넣는다 — 환율 2:1에서 2프랑은 1달러다.
변환하려면 환율을 알아야 하고, 환율은 Bank가 안다. 그런데 Money.reduce(String to)에는 Bank가 없다. 그러니 reduce의 서명을 reduce(Bank bank, String to)로 바꿔 은행을 통째로 넘긴다. Money는 은행에게 환율을 물어 자기 값을 나눈다. 환율표는 Pair(출발 통화, 도착 통화)를 키로 하는 해시테이블에 담는다.
사이클: 서명 변경 → Pair 환율표
class Money implements Expression { public Money reduce(Bank bank, String to) { int rate = bank.rate(currency, to); return new Money(amount / rate, to); } // ...}class Bank { Money reduce(Expression source, String to) { return source.reduce(this, to); } int rate(String from, String to) { return 1; }}// dollar(1) → USD 는 rate 1 이라 그대로. testReduceMoney 초록.// franc(2) → USD 는 rate가 2여야 하는데 1이라 2가 나온다. 빨강.
Pair.hashCode가 return 0인 게 눈에 걸린다. 모든 Pair가 같은 버킷에 들어가 해시테이블이 사실상 리스트가 된다 — 느리다. 하지만 벡은 여기서 멈춘다. 환율표는 작고, 지금 필요한 건 정확성이지 성능이 아니다. 성능은 프로파일러가 여기를 가리킬 때 고치면 된다. 할 일 목록에 “Pair.hashCode 개선”을 적어두고 넘어간다.
같은 통화의 환율을 1로 특별 처리하는 if (from.equals(to)) return 1도 눈여겨볼 만하다. 이 한 줄이 13장의 Money.reduce가 하던 “같은 통화면 그대로”를 환율표 하나로 흡수한다 — 특수 경우를 일반 규칙의 한 값으로 녹였다.
판단 기준: 메서드가 협력자를 필요로 하면, 그 협력자를 인자로 넘기는 것을 두려워하지 않는다. reduce(Bank, String)는 서명이 길어졌지만 Money가 환율을 스스로 구할 수 있게 됐다. 함정: hashCode를 완벽하게 만들려고 멈추는 것. 지금 테스트를 통과시키는 가장 단순한 구현으로 초록을 만들고, 개선은 목록에 남긴다.
이 장이 남긴 할 일 목록
환율이 다른 통화 환산(2프랑 → 1달러)Bank.addRate / rate- Pair.hashCode 개선 (지금 0)
- 10 — 서로 다른 통화의 덧셈 → 15장
다음장으로 15장