8章 オブジェクトの生成

FrancとDollarのtimesは似ている


Moneyを返すようにすれば一致させることが可能


Francのtimesメソッド

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

テスト


Dollarのtimesメソッド

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

テスト


次の手順は明確でない

Franc、Dollarは、存在を正当化するほどの動作を行っていない、削除したい

  • timesメソッドのことですよね?
  • サブクラス自体のことを言っている?


サブクラスへの直接参照が現象すれば、削除へ近づく


Dollarを返す、Moneyのファクトリメソッドを導入


まずはテストクラスから

public void testMultiplication() {
	Dollar five = Money.dollar(5);
	assertEquals(new Dollar(10), five.times(2));
	assertEquals(new Dollar(15), five.times(3));
}

Eclipseのエラーを修正

  • Moneyクラスのimport
  • Moneyクラスへのdollarメソッドの追加


テスト>レッド


Moneyクラスで、Dollarを作成して返す

public 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));

Eclipseのエラーを修正

  • Moneyにtimesメソッドを作成
  • ひとまずテスト>グリーン


Moneyにtimesメソッドを作る準備ができていない
Money.timesメソッドを抽象化する

public abstract Money times(int i);

もちろん、Moneyクラスを抽象クラスに

public abstract class Money {

テスト>グリーン

ここでMoney.dollarメソッドを変更可能に

public static Money dollar(int amount) {
	return new Dollar(amount);
}

テスト>グリーン


テスト内のすべての箇所でファクトリメソッドを使用可能

public void testMultiplication() {
	Money five = Money.dollar(5);
	assertEquals(Money.dollar(10), five.times(2));
	assertEquals(Money.dollar(15), five.times(3));
}
public void testEqaulity(){
	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)));

	//FrancとDollarの比較
	assertFalse(new Franc(5).equals(Money.dollar(5)));
}

クライアントはDollarというサブクラスをクライアントコードはしらない
テストをサブクラスから分離したことで、どのモデルコードに影響を与えずに継承を自由に変更可能になった
timesメソッドは抽象化されたし、Money.dollarメソッドはサブクラスを容易に差し替え可能になった


次、testFrancMultiplicationを変更する前に、testMultiplication=Dollarの乗算用テストについて
すべてのロジックがテストされている
テストを削除すると、コードに対して自信を失うだろうか?

  • テストクラスからみてサブクラスは関係なくなったということ?

本では、釈然としないが、そのままにしておく


では、Francについても同様に
Moneyクラス

public static Money franc(int amount) {
	return new Franc(amount);
}

テストクラス

public void testMultiplication() {
	Money five = Money.dollar(5);
	assertEquals(Money.dollar(10), five.times(2));
	assertEquals(Money.dollar(15), five.times(3));
}
public void testEqaulity(){
	assertTrue(Money.dollar(5).equals(Money.dollar(5)));
	assertFalse(Money.dollar(5).equals(Money.dollar(6)));
	assertTrue(Money.franc(5).equals(Money.franc(5)));
	assertFalse(Money.franc(5).equals(Money.franc(6)));

	//FrancとDollarの比較
	assertFalse(Money.franc(5).equals(Money.dollar(5)));
}
public void testFrancMultiplication() {
	Money five = Money.franc(5);
	assertEquals(Money.franc(10), five.times(2));
	
	assertEquals(Money.franc(15), five.times(3));
}

Money.dollarとおなじ


まとめ

  • 同じメソッド、timesをMoneyという同一のシグニチャを利用することで、除々に重複を取り除いた
  • dollar、francメソッドのこと、スーパークラスへ宣言の移動
  • ファクトリメソッドの導入で、具象クラスの存在をテストから分離
  • サブクラスが範囲外になったので、テストが不要になることはわかったが、行動にはうつさなかった
    • これがさっきのテストを削除する話に繋がっている

次はtimesメソッドの重複を取り除く
わかりやすくなってきた。
しかもテストを用意している効果が分かりやすくなってきた気がする。