# 돌아온 '모두를 위한 평등'

앞 과정에서 하나의 테스트를 통과하기 위해 엄청난 중복 코드를 만들었기 때문에, 이제 중복 코드를 제거하는 리팩토링을 할 시간이다.&#x20;

우선, Dollar와 Franc 두 클래스에서 Money 라는 공통 클래스를 구성하고 equals 코드를 갖게 하면 어떨까?&#x20;

할일 목록을 업데이트 하고, 하나씩 진행해보자.

{% tabs %}
{% tab title="테스트 목록" %}

* $5 + 10CHF = $10(환율이 2:1 일 경우) &#x20;
* ~~*$5 \** 2 = 10$~~&#x20;
* \~\~*amount를 private으로 만들기* \~\~&#x20;
* ~~Dollar 부작용(side effect)?~~&#x20;
* Money 반올림?
* ~~equals()~~
* hashCode()
* Equal null
* Equal object
* ~~5CHF \* 2 = 10CHF~~
* Dollar/Franc 중복
* **공용 equals**
* 공용 time
  {% endtab %}
  {% endtabs %}

## Money 공통 클래스

공통 Money 클래스를 생성하고 테스트를 진행해보자.

```java
public class Money {
}
```

�무리없이 테스트가 통과한다.

다음으로 Dollar가 Money를 상속하도록 변경하고 테스트해본다.

```java
public class Dollar extends Money {
    private int amount;

    public Dollar(int amount) {
        this.amount = amount;

    }

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

    }

    public boolean equals(Object object) {
        Dollar dollar = (Dollar) object;
        return amount == dollar.amount;

    }

}
```

�테스트 모두 잘 동작한다.

이제 amount 인스턴스 변수를 Money 로 옮기며 Dollar 클래스에서 참조 가능하게끔 protected 접근 범위로 변경한다.

```java
public class Money {
    protected int amount;
    
}�
```

## Money Equals

이어서, equals() 메서드를 Money 클래스로 옮기는 작업을 천천히 진행해보자.

첫 번째로 임시변수 타입을 상위 타입으로 변경한다.

```java
public boolean equals(Object object) {
    Money dollar = (Dollar) object;
    return amount == dollar.amount;

}
```

�모든 테스트는 여전히 잘 돈다.

다음으로 캐스팅(cast) 타입도 변경해서 테스트 해보자.

```java
public boolean equals(Object object) {
    Money dollar = (Money) object;
    return amount == dollar.amount;

}
```

�테스트는 잘 동작하며, 조금 더 명확하게 변수명을 money로 변경해보자.

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

}
```

마지막으 equals 메서드를 Money 클래스로 옮겨보자.

```java
public class Money {
    protected int amount;

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

    }

}
```

![](/files/-LsfMDbk6bRiBjU18Vx3)

## 적절한 테스트가 없는 코드에서의 TDD

Franc equals 도 제거해야 할 차례이다. 여기서 문제는 Franc 객체간의 동치성 테스트를 하지 않았다는 점이다.&#x20;

적절한 테스트가 없는 경우, 어떻게 접근해야 할까?

충분한 테스트가 존재하지 않는다면 지원 테스트가 잘 갖춰지지 않은 리팩토링을 만날 수 밖에 없다. 결국, 리팩토링하면서 실수하였는데도 불구하고 여전히 테스트를 통과하는 위험을 초래할 수 있다.&#x20;

어쩔 수 없다. 개발자 스스로가 리팩토링 전에 있으면 좋을 것이라고 생각하는 테스트를 작성하 그 범위를 좁혀 나가야만 한다.

Franc equals 경우에는 Dollar 동치성 테스트를 복사하면 된다.

```java
@Test
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)));
    
}�
```

## 동일한 중복코드로 만들어 제거하&#x20;

이제 Dollar equals 와 동일하게 Franc equals 도 점진적으로 제거해 나간다.

Money 타입을 상속받고, amount 인스턴스 변수를 제거해보자.

```java
public class Franc extends Money {
    public Franc(int amount) {
        this.amount = amount;

    }

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

    }

    public boolean equals(Object object) {
        Franc franc = (Franc) object;
        return amount == franc.amount;

    }

}
```

�테스트는 여전히 잘 동작한다.

이제 Franc.equals() 와 Money.equals() 가 비슷해보이며, **완전히 동일하게 만들 수 있다면 프로그램의 의미를 변화시키지 않고** Franc.equals() 를 **제거할 수 있을 것**이다.

임시변수의 Franc 타입을 Money 로 변경해보자.

```java
public boolean equals(Object object) {
    Money franc = (Franc) object;
    return amount == franc.amount;

}
```

다음으로 캐스팅도 상위 타입으로 변경한다.

```java
public boolean equals(Object object) {
    Money franc = (Money) object;
    return amount == franc.amount;

}
```

�결과적으로, Money.equals() 와 Franc.equals()는 완벽히 동일하기 때문에 Franc.equals()를 제거할 수 있다.

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

}
```

�테스트 또한, 잘 동작하고 있다. 할일 목록에서 하나 더 선을 그을 수 있게 되었다.

{% tabs %}
{% tab title="테스트 목록" %}

* $5 + 10CHF = $10(환율이 2:1 일 경우) &#x20;
* ~~*$5 \** 2 = 10$~~&#x20;
* \~\~*amount를 private으로 만들기* \~\~&#x20;
* ~~Dollar 부작용(side effect)?~~&#x20;
* Money 반올림?
* ~~equals()~~
* hashCode()
* Equal null
* Equal object
* ~~5CHF \* 2 = 10CHF~~
* Dollar/Franc 중복
* ~~공용 equals~~
* 공용 time
* Franc과 Dollar 비교하기
  {% endtab %}
  {% endtabs %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://koseungbin.gitbook.io/wiki/books/undefined-3/1/undefined-4.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
