10章 興味深い時(times)

timesメソッドってなにしてたんだっけかね?(w
そろそろ後半戦かな?


二つのtimes()の実装は似ているが同じではない
前進するための後進

ファクトリメソッドのインライン化
まずは、Francクラスから
Eclipseリファクタリング機能を使う


alt+shift+i

public Money times(int multiplier) {
	return new Franc(amount* multiplier, "CHF");
}

次に、Dollarクラス

public Money times(int multiplier) {
	return new Dollar(amount * multiplier, "USD");
}

テスト>グリーン


currencyインスタンスは常に一定


Franc#times()を変更

public Money times(int multiplier) {
	return new Franc(amount* multiplier, currency);
}

ほぼ完成?Franc、Moneyの存在について


テストには

  • 綺麗なコードを所有し、正しく動作するという自信を与えるテスト
  • 疑わしい推論に時間をかけるのではなく、変化させて、コンピュータにたずねる


テストの存在意義

  • テストなし>論理的に答えを導かなくてはならない
  • テストあり>実験して、質問にもっと速く答えられるかどうかを判断できる


Franc#times()で、Money返すように変更

public Money times(int multiplier) {
	return new Money(amount* multiplier, currency);
}

Eclipseでエラー
#インスタンスの生成ができない

Moneyクラスを具象クラスに

public class Money {

Money#times()メソッドを記述

public Money times(int i) {
	return null;
}

テスト>レッド


エラーを分かりやすくするため、MoneyクラスにtoSting()を定義

@Override
public String toString() {
	return amount + "/ " + currency;
}


この追加のためのテストは、省略
ポリシーとして

  • デバッグ
  • すでにレッドが表示されているときはテストを追加したくない


テスト

junit.framework.AssertionFailedError: expected:<10/ CHF> but was:<10/ CHF>

データはあっているけど、クラスが違う


問題はMoney#equals()の実装

public boolean equals(Object object) {
	Money money = (Money) object;
	return amount == money.amount && getClass().equals(money.getClass());
}

本来は、クラスでなく、通貨が同じであることを調べるべき

保守的な進め方

  • レッドバーの原因になった変更を取り消し
  • equals()用のテストを変更
  • 実装を修正
  • 元の変更を再試行


Franc#times()を戻す

public Money times(int multiplier) {
	return new Franc(amount* multiplier, currency);
}

テスト>グリーン


等しいのに等しくないとされたテストを正確に変換する

public void testDiffClassEqaulity(){
	assertTrue(new Money(10,"CHF").equals(new Franc(10,"CHF")));
}

テスト>レッド
予想どうり


equalsはクラスではなく通貨を比較
Money#equals()を変更

public boolean equals(Object object) {
	Money money = (Money) object;
	return amount == money.amount && currency().equals(money.currency());
}

テスト>グリーン


Fracクラスの実装を元に戻す

public Money times(int multiplier) {
	return new Money(amount* multiplier, currency);
}

テスト>グリーン


Dollarクラスも同様にしてテストが通ることを確認
スーパークラスMoneyに移動することができる
リファクタリング>プルアップ

public Money times(int multiplier) {
	return new Money(amount * multiplier, currency);
}

テスト>グリーン


乗算もサブクラスから取り除いたのでサブクラスを取り除く準備ができた。