본문으둜 κ±΄λ„ˆλ›°κΈ°

🌈 Chapter 10: ν₯미둜운 μ‹œκ°„

두 times() κ΅¬ν˜„μ΄ 거의 λΉ„μŠ·ν•˜κΈ° ν•˜μ§€λ§Œ 아직 μ™„μ „νžˆ λ™μΌν•˜μ§€λŠ” μ•Šλ‹€.

// Franc
Money times(int multiplier) {
return Money.franc(amount * multiplier);
}

// Dollar
Money times(int multiplier) {
return Money.dollar(amount * multiplier);
}

이 λ‘˜μ„ λ™μΌν•˜κ²Œ λ§Œλ“€κΈ° μœ„ν•œ λͺ…λ°±ν•œ 방법이 μ—†λ‹€. λ•Œλ‘œλŠ” μ „μ§„ν•˜κΈ° μœ„ν•΄μ„œ λ¬ΌλŸ¬μ„œμ•Ό ν•  λ•Œλ„ μžˆλŠ” 법이닀. νŒ©ν† λ¦¬ λ©”μ„œλ“œλ₯Ό μΈλΌμΈμ‹œν‚€λ©΄ μ–΄λ–¨κΉŒ?

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

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

Francμ—μ„œλŠ” μΈμŠ€ν„΄μŠ€ λ³€μˆ˜ currencyκ°€ 항상 CHFμ΄λ―€λ‘œ λ‹€μŒκ³Ό 같이 μ“Έ 수 μžˆλ‹€.

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

잘 λŒμ•„κ°„λ‹€. Dollar도 λ§ˆμ°¬κ°€μ§€λ‘œ κ³ μΉ  수 μžˆλ‹€.

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

Franc을 κ°€μ§ˆμ§€ Moneyλ₯Ό κ°€μ§ˆμ§€κ°€ μ •λ§λ‘œ μ€‘μš”ν•œ 사싀인가? μ‹œμŠ€ν…œμ— λŒ€ν•΄ μ•„λŠ” 지식을 기반으둜 μ‘°μ‹¬μŠ€λŸ½κ²Œ 생각해보아 ν•  λ¬Έμ œλ‹€. ν•˜μ§€λ§Œ μš°λ¦¬μ—κ² κΉ”λ”ν•œ μ½”λ“œμ™€ κ·Έ μ½”λ“œκ°€ 잘 μž‘λ™ν•  κ±°λΌλŠ” λ―ΏμŒμ„ 쀄 수 μžˆλŠ” ν…ŒμŠ€νŠΈ μ½”λ“œλ“€μ΄ μžˆλ‹€. λͺ‡ λΆ„ λ™μ•ˆ κ³ λ―Όν•˜λŠ” λŒ€μ‹  κ·Έλƒ₯ μˆ˜μ •ν•˜κ³  ν…ŒμŠ€νŠΈλ₯Ό λŒλ €μ„œ μ»΄ν“¨ν„°μ—κ²Œ 직접 λ¬Όμ–΄λ³΄μž. TDDλ₯Ό κ°€λ₯΄μΉ˜λ‹€λ³΄λ©΄ 항상 이런 상황을 보게 λœλ‹€. 컴퓨터라면 10μ΄ˆμ—μ„œ 15초 사이에 λŒ€λ‹΅ν•  수 μžˆλŠ” 문제λ₯Ό 놓고 졜고의 μ†Œν”„νŠΈμ›¨μ–΄ μ—”μ§€λ‹ˆμ–΄λ“€μ΄ 5λΆ„μ—μ„œ 10λΆ„ λ™μ•ˆ κ³ λ―Όν•˜κ³€ ν•œλ‹€. 가끔은 κ·Έλƒ₯ μ»΄ν“¨ν„°μ—κ²Œ λ¬Όμ–΄λ³΄λŠ” 것도 μ’‹λ‹€.

μ‹€ν—˜μ„ μ‹€ν–‰ν•˜κΈ° μœ„ν•΄ Franc.times()κ°€ Moneyλ₯Ό λ°˜ν™˜ν•˜λ„λ‘ 고쳐보자.

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

μ»΄νŒŒμΌλŸ¬κ°€ Moneyλ₯Ό 콘크리트 클래슀둜 λ°”κΏ”μ•Ό ν•œλ‹€κ³  λ§ν•œλ‹€.

// Money
class Money {
Money times(int amount) {
return null;
}
}

λΉ¨κ°„ λ§‰λŒ€λ‹€. μ—λŸ¬ λ©”μ‹œμ§€μ—λŠ” κΈ°λŒ€λ§ŒνΌ 도움이 λ˜λŠ” λ©”μ‹œμ§€κ°€ μ•„λ‹Œ 것 κ°™λ‹€. 더 λ‚˜μ€ λ©”μ‹œμ§€λ₯Ό 보기 μœ„ν•΄ toString()을 μ •μ˜ν•˜μž.

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

ν—‰! ν…ŒμŠ€νŠΈλ„ 없이 μ½”λ“œλ₯Ό μž‘μ„±ν•˜λ„€? κ·Έλž˜λ„ λ˜λŠ” 건가? toString()을 μž‘μ„±ν•˜κΈ° 전에 ν…ŒμŠ€νŠΈλ₯Ό μž‘μ„±ν•˜λŠ” 게 λ§žλ‹€. ν•˜μ§€λ§Œ

  • 우린 μ§€κΈˆ 화면에 λ‚˜νƒ€λ‚˜λŠ” κ²°κ³Όλ₯Ό 보렀던 참이닀.
  • toString()은 디버그 좜λ ₯μ—λ§Œ 쓰이기 λ•Œλ¬Έμ— 이게 잘λͺ» κ΅¬ν˜„λ¨μœΌλ‘œ 인해 μ–»κ²Œ 될 λ¦¬μŠ€ν¬κ°€ 적닀.
  • 이미 λΉ¨κ°„ λ§‰λŒ€ μƒνƒœμΈλ° 이 μƒνƒœμ—μ„œλŠ” μƒˆλ‘œμš΄ ν…ŒμŠ€νŠΈλ₯Ό μž‘μ„±ν•˜μ§€ μ•ŠλŠ” 게 쒋을 것 κ°™λ‹€.

Franc λŒ€μ‹  Moneyκ°€ μ™”λ‹€. λ¬Έμ œλŠ” equals() κ΅¬ν˜„μ— μžˆλ‹€.

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

μ •λ§λ‘œ 검사해야 ν•  것은 ν΄λž˜μŠ€κ°€ 같은지가 μ•„λ‹ˆλΌ currencyκ°€ 같은지 μ—¬λΆ€λ‹€.

λΉ¨κ°„ λ§‰λŒ€μΈ μƒν™©μ—μ„œλŠ” ν…ŒμŠ€νŠΈλ₯Ό μΆ”κ°€λ‘œ μž‘μ„±ν•˜κ³  싢지 μ•Šλ‹€. ν•˜μ§€λ§Œ μ§€κΈˆμ€ μ‹€μ œ λͺ¨λΈ μ½”λ“œλ₯Ό μˆ˜μ •ν•˜λ €κ³  ν•˜λŠ” 쀑이고 ν…ŒμŠ€νŠΈ μ—†μ΄λŠ” λͺ¨λΈ μ½”λ“œλ₯Ό μˆ˜μ •ν•  수 μ—†λ‹€. 보수적인 λ°©λ²•μœΌλ‘œ λ”°λ₯΄μžλ©΄ λ³€κ²½λœ μ½”λ“œλ₯Ό λ˜λŒλ €μ„œ λ‹€μ‹œ 초둝 λ§‰λŒ€ μƒνƒœλ‘œ λ‘˜μ•„κ°€μ•Ό ν•œλ‹€. 그러고 λ‚˜μ„œ equals()λ₯Ό μœ„ν•΄ ν…ŒμŠ€νŠΈλ₯Ό 고치고 κ΅¬ν˜„ μ½”λ“œλ₯Ό κ³ μΉ  수 있게 되고, κ·Έ 후에야 μ›λž˜ ν•˜λ˜ 일을 λ‹€μ‹œ ν•  수 μžˆλ‹€.
μ΄λ²ˆμ—λŠ” 보수적으둜 ν•΄λ³΄μž.

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

λ‹€μ‹œ 초둝 λ§‰λŒ€λ‘œ λŒμ•„μ™”λ‹€. 우리 상황은 Franc(10, "CHF")κ³Ό Money(10, "CHF")κ°€ μ„œλ‘œ κ°™κΈ°λ₯Ό λ°”λΌμ§€λ§Œ, 사싀은 그렇지 μ•Šλ‹€κ³  보고된 것이닀. μš°λ¦¬λŠ” 이걸 κ·ΈλŒ€λ‘œ ν…ŒμŠ€νŠΈλ‘œ μ‚¬μš©ν•  수 μžˆλ‹€.

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

μ˜ˆμƒλŒ€λ‘œ μ‹€νŒ¨ν•œλ‹€. equals() μ½”λ“œλŠ” ν΄λž˜μŠ€κ°€ μ•„λ‹ˆλΌ currencyλ₯Ό 비ꡐ해야 ν•œλ‹€.

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

이제 Franc.times()μ—μ„œ Moneyλ₯Ό λ°˜ν™˜ν•΄λ„ ν…ŒμŠ€νŠΈκ°€ μ—¬μ „νžˆ ν†΅κ³Όν•˜κ²Œ ν•  수 μžˆλ‹€.

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

이게 Dollar.times()에도 적용될까?

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

잘 λœλ‹€! 이제 두 κ΅¬ν˜„μ΄ λ™μΌν•΄μ‘ŒμœΌλ‹ˆ, μƒμœ„ 클래슀둜 λŒμ–΄ 올릴 수 μžˆγ„·.

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

κ³±ν•˜κΈ°λ„ κ΅¬ν˜„ν–ˆμœΌλ‹ˆ 이제 아무것도 μ•ˆ ν•˜λŠ” λ©μ²­ν•œ ν•˜μœ„ ν΄λž˜μŠ€λ“€μ„ μ œκ±°ν•  수 μžˆκ² λ‹€.