1부 9장 우리가 사는 시간

김희윤·2021년 4월 2일
0

테스트주도개발

목록 보기
9/16

< 현재 구현해야할 목록 >

  • $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 비교하기
  • 통화?

불필요한 하위 클래스를 제거하기 위해서 통화 개념을 도입해보자.

  • Money class 에 currency() 메서드를 선언한다.
abstract class Money {
    protected int amount;
    abstract Money times(int multiplier);
    abstract String currency();
    
    public boolean equals(Object object) {
        Money money = (Money) object;
        return amount == money.amount && getClass().equals(money.getClass());
    }

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

    static Money franc(int amount) {
        return new Franc(amount);
    }
}
  • 두 하위 클래스에서 currency()를 구현한다.

// Franc
public class Franc extends Money{

    public Franc(int amount) {
        this.amount = amount;
    }

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

    @Override
    String currency() {
        return "CHF";
    }

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

// Dollar
public class Dollar extends Money {
    public Dollar(int amount) {
        this.amount = amount;
    }

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

    @Override
    String currency() {
        return "USD";
    }

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

우리는 두 클래스를 모두 포함할 수 있는 동일한 구현을 원한다.
-> 통화를 인스턴스 변수에 저장하고, 메서더는 그것을 반환만하게 만들어 보자.


// Money
abstract class Money {
    protected int amount;
    abstract Money times(int multiplier);
    protected String currency;

    String currency() {
        return currency;
    }

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

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

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

// Franc
public class Franc extends Money{
    private String currency;
    public Franc(int amount) {
        this.amount = amount;
    }

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

    Franc(int amount) {
        this.amount = amount;
        currency = "CHF";
    }
    @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;
    public Dollar(int amount) {
        this.amount = amount;
    }

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

    Dollar(int amount) {
        this.amount = amount;
        currency = "USD";
    }
    @Override
    String currency() {
        return currency;
    }

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

이렇게 바꾸면 에러가 발생한다. 우선은 놔두고 times()를 먼저 정리하자.


// Money
abstract class Money {
    protected int amount;
    abstract Money times(int multiplier);
    protected String currency;

    String currency() {
        return currency;
    }

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

    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;
    public Franc(int amount) {
        this.amount = amount;
    }

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

    Franc(int amount, String currency) {
        this.amount = amount;
        this.currency = 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;
    public Dollar(int amount) {
        this.amount = amount;
    }

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

    Dollar(int amount, String currency) {
        this.amount = amount;
        this.currency = currency;
    }
    @Override
    String currency() {
        return currency;
    }

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

이제 두 생성장가 동일해졌기 때문에 구현을 상위 클래스에 올릴 수 있다.

// Money
abstract class Money {
    protected int amount;
    abstract Money times(int multiplier);
    protected String currency;

    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 Money.franc(amount * multiplier);
    }
    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 Money.dollar( amount * multiplier);
    }

    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;
    }
}

< 현재 구현해야할 목록 >

  • $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()의 리팩토링을 잠시 중단했다.
  • 동일한 생성자들을 상위 클래스로 옮겼다.
profile
블록체인, IOT, 클라우드에 관심이 많은 개발자 지망생

0개의 댓글

관련 채용 정보