1부 10장 흥미로운 시간

< 현재 구현해야할 목록 >

  • $5 + 10CHF = $10 (환율이 2:1일 경우)
  • $5 * 2 = $10
  • amount를 private로 만들기
  • Dollar 부작용
  • Money 반올림
  • equals()
  • hashCode()
  • Equal null
  • Equal object
  • ~~ 5CHF * 2 = 10CHF~~
  • Dollar/Franc 중복제거
  • 공용 equals
  • 공용 times
  • Franc과 Dollar 비교하기
  • 통화?
  • testFrancMultiplication 제거

이 부분에서는 Money를 나타내기 위한 단 하나의 클래스만을 가지게 될 것이다. 두 times()의 구현이 거의 비슷하기는 하지만 아직 완전히 동일하지는 않다.

둘을 살펴봐도 동일하게 만들기 위한 방법이 생각나지 않는다. 따라서 이전에서 한 작업을 다시 되돌려 보자

// Franc
public class Franc extends Money{
    private String currency;

    Money times(int multiplier) {
        return new Franc(amount * multiplier, currency);
    }
    Franc(int amount, String currency) {
        super(amount, currency);
    }
    @Override
    String currency() {
        return currency;
    }

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

// Dollar
public class Dollar extends Money {
    private String currency;

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

    Dollar(int amount, String currency) {
        super(amount, currency);
    }
    @Override
    String currency() {
        return currency;
    }

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

바꾸고보니 Franc을 반환할지 Money를 반환할지가 중요한 문제인가?

때로는 고민보다 코드를 작성해서 컴퓨터에게 물어보는 것이 빠르다.


// Money
abstract class Money {
    protected int amount;
    protected String currency;
    
    public String toString() {
        return amount + " " + currency
    }
    
    Money times(int multiplier) {
        return null;
    }

    String currency() {
        return currency;
    }

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

    Money(int amount, String currency) {
        this.amount = amount;
        this.currency = currency;
    }

    static Money dollar(int amount) {
        return new Dollar(amount, "USD");
    }

    static Money franc(int amount) {
        return new Franc(amount, "CHF");
    }
}

// Franc
public class Franc extends Money{
    private String currency;

    Money times(int multiplier) {
        return new Franc(amount * multiplier, currency);
    }
    Franc(int amount, String currency) {
        super(amount, currency);
    }
    @Override
    String currency() {
        return currency;
    }

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

이렇게 작성하면 에러가 뜬다.

이유는 equals() 구현에 있다. equals()는 클래스가 아니라 currency를 비교해야 한다.


// Money
class Money {
    protected int amount;
    protected String currency;

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

    Money times(int multiplier) {
        return null;
    }

    String currency() {
        return currency;
    }

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

    Money(int amount, String currency) {
        this.amount = amount;
        this.currency = currency;
    }

    static Money dollar(int amount) {
        return new Dollar(amount, "USD");
    }

    static Money franc(int amount) {
        return new Franc(amount, "CHF");
    }
}

// Franc
public class Franc extends Money{
    private String currency;

    Money times(int multiplier) {
        return new Money(amount * multiplier, currency);
    }
    Franc(int amount, String currency) {
        super(amount, currency);
    }
    @Override
    String currency() {
        return currency;
    }

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

// Dollar
public class Dollar extends Money {
    private String currency;

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

    Dollar(int amount, String currency) {
        super(amount, currency);
    }
    @Override
    String currency() {
        return currency;
    }

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

이제 두 구현이 동일해졌으니 상위 클래스로 끌어 올릴 수 있다.

class Money {
    protected int amount;
    protected String currency;

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

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

    String currency() {
        return currency;
    }

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

    Money(int amount, String currency) {
        this.amount = amount;
        this.currency = currency;
    }

    static Money dollar(int amount) {
        return new Dollar(amount, "USD");
    }

    static Money franc(int amount) {
        return new Franc(amount, "CHF");
    }
}

< 현재 구현해야할 목록 >

  • $5 + 10CHF = $10 (환율이 2:1일 경우)
  • $5 * 2 = $10
  • amount를 private로 만들기
  • Dollar 부작용
  • Money 반올림
  • equals()
  • hashCode()
  • Equal null
  • Equal object
  • ~~ 5CHF * 2 = 10CHF~~
  • Dollar/Franc 중복제거
  • 공용 equals
  • 공용 times
  • Franc과 Dollar 비교하기
  • 통화?
  • testFrancMultiplication 제거

우리는 지금까지

  • 두 times()를 일치시키기 위해 메서드들이 호출하는 다른 메서드들을 인라인시킨 후 상수를 변수로 바꿔주었다.
  • 단지 디버깅을 위해서 테스트 없이 toString()을 작성했다.
  • Franc 대신 Money를 반환하는 변경을 시도한 뒤 그것이 잘 작동할지를 테스트했다.
  • 실험해본 걸 뒤로 물리고 또 다른 테스트를 작성했다.

좋은 웹페이지 즐겨찾기