章節概述#

上一章結尾冒出了一個令人不安的問題:如果拿 Franc 和 Dollar 比較,會發生什麼事? 本章要面對這個問題,確保不同貨幣之間的等值比較是正確的。

問題浮現:Franc 等於 Dollar?#

將這個擔憂轉化為測試:

public void testEquality() {
    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)));
    assertFalse(new Franc(5).equals(new Dollar(5)));
}

最後一行是新增的——5 Franc 不應該等於 5 Dollar。但測試失敗了:目前的 equals() 只比較金額,沒有區分貨幣類型,因此 Dollar 和 Franc 被視為相等。

用 getClass() 修正#

修正方式是在 equals() 中加入類別檢查——兩個 Money 物件只有在金額和類別都相同時才相等:

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

測試通過了。

補充: 作者承認在模型程式碼中使用 getClass() 有點「壞味道(code smell)」。理想上應該用業務領域中有意義的概念(如貨幣 currency)來區分,而不是 Java 物件的類別。但目前尚未引入 currency 的概念,而且僅為此引入似乎理由不夠充分,所以暫時這樣處理。

更新後的待辦清單#

清單上劃掉了「Compare Francs with Dollars」,同時新增了一個疑問:

  • Compare Francs to Dollars
  • Currency?(新增)

接下來需要消除 times() 的重複,才能進入混合貨幣運算。

本章小結#

  • 將一個令人困擾的疑慮轉化為測試
  • 用合理但不完美的方式(getClass())讓測試通過
  • 決定不過早引入更多設計,直到有更好的動機