6章 再度、すべてに対する等価性
5章でテストを早くパスするために、あえてコピペという罪を犯してかいたコードを綺麗にする
綺麗にするには
- あるクラスの拡張クラスを作るより
- 共通のスーパークラスを作る
- それぞれ下位のクラスに対して、等価性がある
各変更ごとにテストを行う
Moneyクラスというスーパークラスを作成
package star; public class Money { }
DollarクラスをMoneyクラスの拡張とする
public class Dollar extends Money { public int amount;
ammountインスタンス変数をMoneyに移動(プルアップ)
Dollar
public class Dollar extends Money {
Money
public class Money { protected int amount; }
equalsメソッドを一般化する準備
一時変数の宣言を変更
2つの作業
public boolean equals(Object object){ Money dollar = (Dollar)object; return amount == dollar.amount; }
public boolean equals(Object object){ Money dollar = (Money)object; return amount == dollar.amount; }
一時変数自体も変更
public boolean equals(Object object){ Money money = (Money)object; return amount == money.amount; }
DollarクラスからMoneyクラスへ、equalsメソッドを移動することが可能(プルアップ)
public class Money { protected int amount; public boolean equals(Object object) { Money money = (Money)object; return amount == money.amount; } }
Franc.equals()について
- 削除する必要あり
- そもそも等価性のテスト(testEqaulity)には、Francは入っていなかった
- テストを作る必要がある
十分なテストがないと、テストによってサポートされないリファクタリングに遭遇する
リファクタリングに失敗してもテストがパスすることがある
解決にはあればよいと思うテストを作る
悪い循環
testEqaulity()にFrancケースを追加
public void testEqaulity(){ 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))); }
FrancクラスをMoneyクラスからの拡張に
- amountフィールドの移動
- eqaulsメソッドの移動:冗長な実装と分かるよう、実装を一致させる
まとめ
- クラスからスーパークラスへと段階的に共通コードを移動
- Francクラスもサブクラス化
次はFrancクラスとDollarクラスの比較