- $5 + 10CHF = $10(환율이 2:1 일 경우)
- $5 X 2 = $10
- amount 를 private 으로 만들기
- Dollar Side Effect
- Money 반올림
- 통화가 다른 두 금액을 더해서 주어진 환율에 맞게 변환된 금액을 얻을 수 있어야 함.
- 금액 X 숫자에 대한 결과를 얻을 수 있어야 함.
위의 기능을 구현하기 위해 어떤 객체를 만들어야 할까? X 위의 기능을 구현하기 위해 어떤 테스트가 필요할까? O
Dollar.java
public class Dollar {
public int amount;
public Dollar(int amount) {
this.amount = amount;
}
public void times(int multiplier) {
amount *= multiplier;
}
}
DollarTest.java
public class DollarTest {
@Test
public void testMultiplication() {
Dollar five = new Dollar(5);
five.times(2);
assertEquals(10, five.amount);
}
}
- $5 + 10CHF = $10(환율이 2:1 일 경우)
$5 X 2 = $10- amount 를 private 으로 만들기
- Dollar Side Effect
- Money 반올림
Dollar.java
public class Dollar {
public int amount;
public Dollar(int amount) {
this.amount = amount;
}
public Dollar times(int multiplier) {
return new Dollar(amount * multiplier);
}
}
DollarTest.java
public class DollarTest {
@Test
public void testMultiplication() {
Dollar five = new Dollar(5);
Dollar product = five.times(2);
assertEquals(10, product.amount);
product = five.times(3);
assertEquals(15, product.amount);
}
}
-
$5 + 10CHF = $10(환율이 2:1 일 경우)
-
$5 X 2 = $10 -
amount 를 private 으로 만들기
-
Dollar Side Effect -
Money 반올림
-
equals()
-
hashCode()
-
Equal null
-
Equal object
Dollar.java
public class Dollar { public 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 this.amount == dollar.amount; } }
DollarTest.java
public class DollarTest { @Test public void testMultiplication() { Dollar five = new Dollar(5); Dollar product = five.times(2); assertEquals(10, product.amount); product = five.times(3); assertEquals(15, product.amount); } @Test public void testEquality() { assertTrue(new Dollar(5).equals(new Dollar(5))); assertFalse(new Dollar(5).equals(new Dollar(6))); } }
- $5 + 10CHF = $10(환율이 2:1 일 경우)
$5 X 2 = $10- amount 를 private 으로 만들기
Dollar Side Effect- Money 반올림
equals()- hashCode()
- Equal null
- Equal object
Dollar.java
public class Dollar {
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 this.amount == dollar.amount;
}
}
DollarTest.java
public class DollarTest {
/**
* 이전의 테스트 코드들과는 달리
* Dollar 의 프로퍼티를 직접 사용하지 않음으로써
* 코드 - 테스트 간 결합도를 낮췄다.
*
* 명심하자 항상.. 결합도는 낮게, 응집도는 높게!!!
*/
@Test
public void testMultiplication() {
Dollar five = new Dollar(5);
assertEquals(new Dollar(10), five.times(2));
assertEquals(new Dollar(15), five.times(3));
}
@Test
public void testEquality() {
assertTrue(new Dollar(5).equals(new Dollar(5)));
assertFalse(new Dollar(5).equals(new Dollar(6)));
}
}
- $5 + 10CHF = $10(환율이 2:1 일 경우)
$5 X 2 = $10amount 를 private 으로 만들기Dollar Side Effect- Money 반올림
equals()- hashCode()
- Equal null
- Equal object
- 5CHF X 2 = 10CHF
Dollar.java
public class Dollar {
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 this.amount == dollar.amount;
}
}
Franc.java
public class Franc {
private int amount;
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 this.amount == franc.amount;
}
}
DollarFrancTest.java
public class DollarFrancTest {
@Test
public void testMultiplication() {
Dollar five = new Dollar(5);
assertEquals(new Dollar(10), five.times(2));
assertEquals(new Dollar(15), five.times(3));
}
@Test
public void testEquality() {
assertTrue(new Dollar(5).equals(new Dollar(5)));
assertFalse(new Dollar(5).equals(new Dollar(6)));
}
@Test
public void testFrancMultiplication() {
Franc five = new Franc(5);
assertEquals(new Franc(10), five.times(2));
assertEquals(new Franc(15), five.times(3));
}
}
- $5 + 10CHF = $10(환율이 2:1 일 경우)
$5 X 2 = $10amount 를 private 으로 만들기Dollar Side Effect- Money 반올림
equals()- hashCode()
- Equal null
- Equal object
5CHF X 2 = 10CHF- Dollar / Franc 중복 코드
- 공용 equals
- 공용 times
Money.java
public class Money {
protected int amount;
public boolean equals(Object object) {
Money money = (Money) object;
return this.amount == money.amount;
}
}
Dollar.java
public class Dollar extends Money {
public Dollar(int amount) {
this.amount = amount;
}
public Dollar times(int multiplier) {
return new Dollar(amount * multiplier);
}
}
Franc.java
public class Franc extends Money {
public Franc(int amount) {
this.amount = amount;
}
public Franc times(int multiplier) {
return new Franc(amount * multiplier);
}
}
DollarFrancTest.java
public class DollarFrancTest {
@Test
public void testMultiplication() {
Dollar five = new Dollar(5);
assertEquals(new Dollar(10), five.times(2));
assertEquals(new Dollar(15), five.times(3));
}
@Test
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)));
}
@Test
public void testFrancMultiplication() {
Franc five = new Franc(5);
assertEquals(new Franc(10), five.times(2));
assertEquals(new Franc(15), five.times(3));
}
}
- $5 + 10CHF = $10(환율이 2:1 일 경우)
$5 X 2 = $10amount 를 private 으로 만들기Dollar Side Effect- Money 반올림
equals()- hashCode()
- Equal null
- Equal object
5CHF X 2 = 10CHF- Dollar / Franc 중복 코드
공용 equals- 공용 times
- Franc 과 Dollar 비교하기
Money.java
public class Money {
protected int amount;
public boolean equals(Object object) {
Money money = (Money) object;
return this.amount == money.amount && getClass().equals(money.getClass());
}
}
Dollar.java
public class Dollar extends Money {
public Dollar(int amount) {
this.amount = amount;
}
public Dollar times(int multiplier) {
return new Dollar(amount * multiplier);
}
}
Franc.java
public class Franc extends Money {
public Franc(int amount) {
this.amount = amount;
}
public Franc times(int multiplier) {
return new Franc(amount * multiplier);
}
}
DollarFrancTest.java
public class DollarFrancTest {
@Test
public void testMultiplication() {
Dollar five = new Dollar(5);
assertEquals(new Dollar(10), five.times(2));
assertEquals(new Dollar(15), five.times(3));
}
@Test
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)));
}
@Test
public void testFrancMultiplication() {
Franc five = new Franc(5);
assertEquals(new Franc(10), five.times(2));
assertEquals(new Franc(15), five.times(3));
}
}
- $5 + 10CHF = $10(환율이 2:1 일 경우)
$5 X 2 = $10amount 를 private 으로 만들기Dollar Side Effect- Money 반올림
equals()- hashCode()
- Equal null
- Equal object
5CHF X 2 = 10CHF- Dollar / Franc 중복 코드
공용 equals- 공용 times
Franc 과 Dollar 비교하기
Money.java
public abstract class Money {
protected int amount;
public static Money dollar(int amount) {
return new Dollar(amount);
}
public static Money franc(int amount) {
return new Franc(amount);
}
abstract Money times(int multiplier);
public boolean equals(Object object) {
Money money = (Money) object;
return this.amount == money.amount && getClass().equals(money.getClass());
}
}
Dollar.java
public class Dollar extends Money {
public Dollar(int amount) {
this.amount = amount;
}
public Money times(int multiplier) {
return new Dollar(amount * multiplier);
}
}
Franc.java
public class Franc extends Money {
public Franc(int amount) {
this.amount = amount;
}
public Money times(int multiplier) {
return new Franc(amount * multiplier);
}
}
DollarFrancTest.java
/**
* Factory Method Pattern 을 사용하여
* 객체 생성에 대한 구체적인 부분을 추상화 함
*/
public class DollarFrancTest {
@Test
public void testMultiplication() {
Money five = Money.dollar(5);
assertEquals(Money.dollar(10), five.times(2));
assertEquals(Money.dollar(15), five.times(3));
}
@Test
public void testEquality() {
assertTrue(Money.dollar(5).equals(Money.dollar(5)));
assertFalse(Money.dollar(5).equals(Money.dollar(6)));
assertTrue(Money.franc(5).equals(Money.franc(5)));
assertFalse(Money.franc(5).equals(Money.franc(6)));
assertFalse(Money.franc(5).equals(new Dollar(5)));
}
@Test
public void testFrancMultiplication() {
Money five = Money.franc(5);
assertEquals(Money.franc(10), five.times(2));
assertEquals(Money.franc(15), five.times(3));
}
}
- $5 + 10CHF = $10(환율이 2:1 일 경우)
$5 X 2 = $10amount 를 private 으로 만들기Dollar Side Effect- Money 반올림
equals()- hashCode()
- Equal null
- Equal object
5CHF X 2 = 10CHF- Dollar / Franc 중복 코드(아직 더 할게 있음)
공용 equals- 공용 times
Franc 과 Dollar 비교하기- 통화?
- testFrancMultiplication 제거
Money.java
public abstract class Money {
protected int amount;
protected String currency;
public Money(int amount, String currency) {
this.amount = amount;
this.currency = currency;
}
public static Money dollar(int amount) {
return new Dollar(amount, "USD");
}
public static Money franc(int amount) {
return new Franc(amount, "CHF");
}
abstract Money times(int multiplier);
public boolean equals(Object object) {
Money money = (Money) object;
return this.amount == money.amount && getClass().equals(money.getClass());
}
public String currency() {
return this.currency;
}
}
Dollar.java
public class Dollar extends Money {
public Dollar(int amount, String currency) {
super(amount, currency);
}
@Override
public Money times(int multiplier) {
return Money.dollar(amount * multiplier);
}
}
Franc.java
public class Franc extends Money {
public Franc(int amount, String currency) {
super(amount, currency);
}
@Override
public Money times(int multiplier) {
return Money.franc(amount * multiplier);
}
}
DollarFrancTest.java
/**
* Factory Method Pattern 을 사용하여
* 객체 생성에 대한 구체적인 부분을 추상화 함
*/
public class DollarFrancTest {
@Test
public void testMultiplication() {
Money five = Money.dollar(5);
assertEquals(Money.dollar(10), five.times(2));
assertEquals(Money.dollar(15), five.times(3));
}
@Test
public void testEquality() {
assertTrue(Money.dollar(5).equals(Money.dollar(5)));
assertFalse(Money.dollar(5).equals(Money.dollar(6)));
assertTrue(Money.franc(5).equals(Money.franc(5)));
assertFalse(Money.franc(5).equals(Money.franc(6)));
assertFalse(Money.franc(5).equals(Money.dollar(5)));
}
@Test
public void testFrancMultiplication() {
Money five = Money.franc(5);
assertEquals(Money.franc(10), five.times(2));
assertEquals(Money.franc(15), five.times(3));
}
@Test
public void testCurrency() {
assertEquals("USD", Money.dollar(1).currency());
assertEquals("CHF", Money.franc(1).currency());
}
}
- $5 + 10CHF = $10(환율이 2:1 일 경우)
$5 X 2 = $10amount 를 private 으로 만들기Dollar Side Effect- Money 반올림
equals()- hashCode()
- Equal null
- Equal object
5CHF X 2 = 10CHF- Dollar / Franc 중복 코드(아직 더 할게 있음)
공용 equals- 공용 times
Franc 과 Dollar 비교하기통화?- testFrancMultiplication 제거
Money.java
public class Money {
protected int amount;
protected String currency;
public Money(int amount, String currency) {
this.amount = amount;
this.currency = currency;
}
public static Money dollar(int amount) {
return new Dollar(amount, "USD");
}
public static Money franc(int amount) {
return new Franc(amount, "CHF");
}
public Money times(int multiplier) {
return new Money(amount * multiplier, currency);
}
public boolean equals(Object object) {
Money money = (Money) object;
return this.amount == money.amount && currency.equals(money.currency());
}
public String currency() {
return this.currency;
}
@Override
public String toString() {
return "Money{" +
"amount=" + amount +
", currency='" + currency + '\'' +
'}';
}
}
Dollar.java
public class Dollar extends Money {
public Dollar(int amount, String currency) {
super(amount, currency);
}
}
Franc.java
public class Franc extends Money {
public Franc(int amount, String currency) {
super(amount, currency);
}
}
DollarFrancTest.java
public class DollarFrancTest {
@Test
public void testMultiplication() {
Money five = Money.dollar(5);
assertEquals(Money.dollar(10), five.times(2));
assertEquals(Money.dollar(15), five.times(3));
}
@Test
public void testEquality() {
assertTrue(Money.dollar(5).equals(Money.dollar(5)));
assertFalse(Money.dollar(5).equals(Money.dollar(6)));
assertTrue(Money.franc(5).equals(Money.franc(5)));
assertFalse(Money.franc(5).equals(Money.franc(6)));
assertFalse(Money.franc(5).equals(Money.dollar(5)));
}
@Test
public void testFrancMultiplication() {
Money five = Money.franc(5);
assertEquals(Money.franc(10), five.times(2));
assertEquals(Money.franc(15), five.times(3));
}
@Test
public void testCurrency() {
assertEquals("USD", Money.dollar(1).currency());
assertEquals("CHF", Money.franc(1).currency());
}
@Test
public void testDifferentClassEquality() {
assertTrue(new Money(10, "CHF").equals(new Franc(10, "CHF")));
}
}
- $5 + 10CHF = $10(환율이 2:1 일 경우)
$5 X 2 = $10amount 를 private 으로 만들기Dollar Side Effect- Money 반올림
equals()- hashCode()
- Equal null
- Equal object
5CHF X 2 = 10CHF- Dollar / Franc 중복 코드(아직 더 할게 있음)
공용 equals공용 timesFranc 과 Dollar 비교하기통화?- testFrancMultiplication 제거
Money.java
public class Money {
protected int amount;
protected String currency;
public Money(int amount, String currency) {
this.amount = amount;
this.currency = currency;
}
public static Money dollar(int amount) {
return new Money(amount, "USD");
}
public static Money franc(int amount) {
return new Money(amount, "CHF");
}
public Money times(int multiplier) {
return new Money(amount * multiplier, currency);
}
public boolean equals(Object object) {
Money money = (Money) object;
return this.amount == money.amount && currency.equals(money.currency());
}
public String currency() {
return this.currency;
}
@Override
public String toString() {
return "Money{" +
"amount=" + amount +
", currency='" + currency + '\'' +
'}';
}
}
MoneyTest.java
public class MoneyTest {
@Test
public void testMultiplication() {
Money five = Money.dollar(5);
assertEquals(Money.dollar(10), five.times(2));
assertEquals(Money.dollar(15), five.times(3));
}
@Test
public void testEquality() {
assertTrue(Money.dollar(5).equals(Money.dollar(5)));
assertFalse(Money.dollar(5).equals(Money.dollar(6)));
assertFalse(Money.franc(5).equals(Money.dollar(5)));
}
@Test
public void testFrancMultiplication() {
Money five = Money.franc(5);
assertEquals(Money.franc(10), five.times(2));
assertEquals(Money.franc(15), five.times(3));
}
@Test
public void testCurrency() {
assertEquals("USD", Money.dollar(1).currency());
assertEquals("CHF", Money.franc(1).currency());
}
}
- $5 + 10CHF = $10(환율이 2:1 일 경우)
- $5 +
$5 = 10$
Expression.java
public interface Expression {
}
Money.java
public class Money implements Expression{
protected int amount;
protected String currency;
public Money(int amount, String currency) {
this.amount = amount;
this.currency = currency;
}
public static Money dollar(int amount) {
return new Money(amount, "USD");
}
public static Money franc(int amount) {
return new Money(amount, "CHF");
}
public Money times(int multiplier) {
return new Money(amount * multiplier, currency);
}
public boolean equals(Object object) {
Money money = (Money) object;
return this.amount == money.amount && currency.equals(money.currency());
}
public String currency() {
return this.currency;
}
@Override
public String toString() {
return "Money{" +
"amount=" + amount +
", currency='" + currency + '\'' +
'}';
}
public Expression plus(Money money) {
return new Money(this.amount + money.amount, this.currency);
}
}
Bank.java
public class Bank {
public Money reduce(Expression sum, String usd) {
return Money.dollar(10);
}
}
MoneyTest.java
public class MoneyTest {
@Test
public void testMultiplication() {
Money five = Money.dollar(5);
assertEquals(Money.dollar(10), five.times(2));
assertEquals(Money.dollar(15), five.times(3));
}
@Test
public void testEquality() {
assertTrue(Money.dollar(5).equals(Money.dollar(5)));
assertFalse(Money.dollar(5).equals(Money.dollar(6)));
assertFalse(Money.franc(5).equals(Money.dollar(5)));
}
@Test
public void testFrancMultiplication() {
Money five = Money.franc(5);
assertEquals(Money.franc(10), five.times(2));
assertEquals(Money.franc(15), five.times(3));
}
@Test
public void testCurrency() {
assertEquals("USD", Money.dollar(1).currency());
assertEquals("CHF", Money.franc(1).currency());
}
@Test
public void testSimpleAddition() {
Money five = Money.dollar(5);
/**
* Money 연산을 Expression 에 위임(Expression 은 Money 의 계산식으로만 취급)
* $5 + $5
*/
Expression sum = five.plus(five);
Bank bank = new Bank();
/**
* Money 의 계산식, 즉 Expression 을 받고, currency Type 을 받는다
* 이 뜻은 Money 의 계산식을 currency Type 에 맞게 계산하는것을
* Bank 가 위임받아서 하고있다는 것을 의미한다.
*
* Ex. Expression : $5 + $5
* Bank : $5 + $5 를 주어진 currency Type 에 맞춘 금액은? => bank.reduce($5 + $5, currency)
*/
Money reduced = bank.reduce(sum, "USD");
assertEquals(Money.dollar(10), reduced);
}
}
- $5 + 10CHF = $10(환율이 2:1 일 경우)
- $5 +
$5 = 10$ (중복이 있음) - $5 + $5 에서 Money 반환하기
- Bank.reduce(Money)
- Money 에 대한 통화 변환을 수행하는 Reduce
- Reduce(Bank, String)
Expression.java
public interface Expression {
Money reduce(String to);
}
Bank.java
public class Bank {
public Money reduce(Expression source, String to) {
return source.reduce(to);
}
}
Money.java
public class Money implements Expression {
protected int amount;
protected String currency;
public Money(int amount, String currency) {
this.amount = amount;
this.currency = currency;
}
public static Money dollar(int amount) {
return new Money(amount, "USD");
}
public static Money franc(int amount) {
return new Money(amount, "CHF");
}
public Money times(int multiplier) {
return new Money(amount * multiplier, currency);
}
public boolean equals(Object object) {
Money money = (Money) object;
return this.amount == money.amount && currency.equals(money.currency());
}
public String currency() {
return this.currency;
}
public Expression plus(Money addend) {
return new Sum(this, addend);
}
@Override
public Money reduce(String to) {
return this;
}
@Override
public String toString() {
return "Money{" +
"amount=" + amount +
", currency='" + currency + '\'' +
'}';
}
}
Sum.java
public class Sum implements Expression{
Money augend;
Money addend;
public Sum(Money augend, Money addend) {
this.augend = augend;
this.addend = addend;
}
public Money reduce(String to) {
int amount = this.augend.amount + this.addend.amount;
return new Money(amount, to);
}
}
MoneyTest.java
public class MoneyTest {
@Test
public void testMultiplication() {
Money five = Money.dollar(5);
assertEquals(Money.dollar(10), five.times(2));
assertEquals(Money.dollar(15), five.times(3));
}
@Test
public void testEquality() {
assertTrue(Money.dollar(5).equals(Money.dollar(5)));
assertFalse(Money.dollar(5).equals(Money.dollar(6)));
assertFalse(Money.franc(5).equals(Money.dollar(5)));
}
@Test
public void testFrancMultiplication() {
Money five = Money.franc(5);
assertEquals(Money.franc(10), five.times(2));
assertEquals(Money.franc(15), five.times(3));
}
@Test
public void testCurrency() {
assertEquals("USD", Money.dollar(1).currency());
assertEquals("CHF", Money.franc(1).currency());
}
@Test
public void testSimpleAddition() {
Money five = Money.dollar(5);
Expression result = five.plus(five);
Sum sum = (Sum) result;
assertEquals(five, sum.augend);
assertEquals(five, sum.addend);
}
@Test
public void testReduceSum() {
Expression sum = new Sum(Money.dollar(3), Money.dollar(4));
Bank bank = new Bank();
Money result = bank.reduce(sum, "USD");
assertEquals(Money.dollar(7), result);
}
@Test
public void testReduceMoney() {
Bank bank = new Bank();
Money result = bank.reduce(Money.dollar(1), "USD");
assertEquals(Money.dollar(1), result);
}
}
- $5 + 10CHF = $10(환율이 2:1 일 경우)
- $5 +
$5 = 10$ (중복이 있음) - $5 + $5 에서 Money 반환하기
Bank.reduce(Money)- Money 에 대한 통화 변환을 수행하는 Reduce
- Reduce(Bank, String)
Pair.java
public class Pair {
private String from;
private String to;
public Pair(String from, String to) {
this.from = from;
this.to = to;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Pair pair = (Pair) o;
return Objects.equals(from, pair.from) &&
Objects.equals(to, pair.to);
}
@Override
public int hashCode() {
return Objects.hash(from, to);
}
}
Expression.java
public interface Expression {
Money reduce(Bank bank, String to);
}
Bank.java
public class Bank {
private Hashtable<Pair, Integer> rates = new Hashtable();
public Money reduce(Expression source, String to) {
return source.reduce(this, to);
}
public void addRate(String from, String to, int rate) {
rates.put(new Pair(from, to), new Integer(rate));
}
public int rate(String from, String to) {
if(from.equals(to)) return 1;
return rates.get(new Pair(from, to)).intValue();
}
}
Money.java
public class Money implements Expression {
protected int amount;
protected String currency;
public Money(int amount, String currency) {
this.amount = amount;
this.currency = currency;
}
public static Money dollar(int amount) {
return new Money(amount, "USD");
}
public static Money franc(int amount) {
return new Money(amount, "CHF");
}
public Money times(int multiplier) {
return new Money(amount * multiplier, currency);
}
public boolean equals(Object object) {
Money money = (Money) object;
return this.amount == money.amount && currency.equals(money.currency());
}
public String currency() {
return this.currency;
}
public Expression plus(Money addend) {
return new Sum(this, addend);
}
@Override
public Money reduce(Bank bank,String to) {
return new Money((amount / bank.rate(this.currency, to)), to);
}
@Override
public String toString() {
return "Money{" +
"amount=" + amount +
", currency='" + currency + '\'' +
'}';
}
}
Sum.java
public class Sum implements Expression {
Money augend;
Money addend;
public Sum(Money augend, Money addend) {
this.augend = augend;
this.addend = addend;
}
public Money reduce(Bank bank, String to) {
int amount = this.augend.amount + this.addend.amount;
return new Money(amount, to);
}
}
- $5 + 10CHF = $10(환율이 2:1 일 경우)
$5 +$5 = 10$ - $5 + $5 에서 Money 반환하기
Bank.reduce(Money)Money 에 대한 통화 변환을 수행하는 ReduceReduce(Bank, String)
Expression.java
public interface Expression {
Money reduce(Bank bank, String to);
Expression plus(Expression addend);
}
Money.java
public class Money implements Expression {
protected int amount;
protected String currency;
public Money(int amount, String currency) {
this.amount = amount;
this.currency = currency;
}
public static Money dollar(int amount) {
return new Money(amount, "USD");
}
public static Money franc(int amount) {
return new Money(amount, "CHF");
}
public Expression times(int multiplier) {
return new Money(amount * multiplier, currency);
}
public boolean equals(Object object) {
Money money = (Money) object;
return this.amount == money.amount && currency.equals(money.currency());
}
public String currency() {
return this.currency;
}
public Expression plus(Expression addend) {
return new Sum(this, addend);
}
@Override
public Money reduce(Bank bank, String to) {
return new Money((amount / bank.rate(this.currency, to)), to);
}
@Override
public String toString() {
return "Money{" +
"amount=" + amount +
", currency='" + currency + '\'' +
'}';
}
}
Sum.java
public class Sum implements Expression {
Expression augend;
Expression addend;
public Sum(Expression augend, Expression addend) {
this.augend = augend;
this.addend = addend;
}
public Money reduce(Bank bank, String to) {
int amount = this.augend.reduce(bank, to).amount + this.addend.reduce(bank, to).amount;
return new Money(amount, to);
}
@Override
public Expression plus(Expression addend) {
return null;
}
}
Bank.java
public class Bank {
private Hashtable<Pair, Integer> rates = new Hashtable();
public Money reduce(Expression source, String to) {
return source.reduce(this, to);
}
public void addRate(String from, String to, int rate) {
rates.put(new Pair(from, to), new Integer(rate));
}
public int rate(String from, String to) {
if(from.equals(to)) return 1;
return rates.get(new Pair(from, to)).intValue();
}
}
Pair.java
public class Pair {
private String from;
private String to;
public Pair(String from, String to) {
this.from = from;
this.to = to;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Pair pair = (Pair) o;
return Objects.equals(from, pair.from) &&
Objects.equals(to, pair.to);
}
@Override
public int hashCode() {
return Objects.hash(from, to);
}
}
$5 + 10CHF = $10(환율이 2:1 일 경우)$5 +$5 = 10$ - $5 + $5 에서 Money 반환하기
Bank.reduce(Money)Money 에 대한 통화 변환을 수행하는 ReduceReduce(Bank, String)- Sum.plus
- Expression.times
Money.java
public class Money implements Expression {
protected int amount;
protected String currency;
public Money(int amount, String currency) {
this.amount = amount;
this.currency = currency;
}
public static Money dollar(int amount) {
return new Money(amount, "USD");
}
public static Money franc(int amount) {
return new Money(amount, "CHF");
}
public Expression times(int multiplier) {
return new Money(amount * multiplier, currency);
}
public boolean equals(Object object) {
Money money = (Money) object;
return this.amount == money.amount && currency.equals(money.currency());
}
public String currency() {
return this.currency;
}
public Expression plus(Expression addend) {
return new Sum(this, addend);
}
@Override
public Money reduce(Bank bank, String to) {
return new Money((amount / bank.rate(this.currency, to)), to);
}
@Override
public String toString() {
return "Money{" +
"amount=" + amount +
", currency='" + currency + '\'' +
'}';
}
}
Sum.java
public class Sum implements Expression {
Expression augend;
Expression addend;
public Sum(Expression augend, Expression addend) {
this.augend = augend;
this.addend = addend;
}
public Money reduce(Bank bank, String to) {
int amount = this.augend.reduce(bank, to).amount + this.addend.reduce(bank, to).amount;
return new Money(amount, to);
}
@Override
public Expression plus(Expression addend) {
return new Sum(this, addend);
}
@Override
public Expression times(int multiplier) {
return new Sum(augend.times(multiplier), addend.times(multiplier));
}
}
Expression.java
public interface Expression {
Money reduce(Bank bank, String to);
Expression plus(Expression addend);
Expression times(int multiplier);
}
Bank.java
public class Bank {
private Hashtable<Pair, Integer> rates = new Hashtable();
public Money reduce(Expression source, String to) {
return source.reduce(this, to);
}
public void addRate(String from, String to, int rate) {
rates.put(new Pair(from, to), new Integer(rate));
}
public int rate(String from, String to) {
if(from.equals(to)) return 1;
return rates.get(new Pair(from, to)).intValue();
}
}
Pair.java
public class Pair {
private String from;
private String to;
public Pair(String from, String to) {
this.from = from;
this.to = to;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Pair pair = (Pair) o;
return Objects.equals(from, pair.from) &&
Objects.equals(to, pair.to);
}
@Override
public int hashCode() {
return Objects.hash(from, to);
}
}
테스트 먼저 작성하고 코드를 작성해나가는 것은 이해되지만,
코드의 중복을 제거해나가며 테스트를 신뢰하며 나아가야하는 내용도 알겠지만...
리팩토링을 하는데 갑자기 Bank, Expression, Pair 등과 같은 아이디어는
어떻게 도출해야하는지 잘모르겠다...
어떻게 도출해내는지 모르니 각 객체의 Role 을 이해못하고,
그래서 어디에 어떤 메서드를 배치해야할지 감을 못잡겠다.