TDD入門自分用メモ-20141121


# Part 1-8

* 構造が似ているメソッドの...

``` Dollar.java

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

```
``` Franc.java

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

```

* シグニチャを一致させる

``` Dollar.java

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

```
``` Franc.java

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

```

* サブクラスへの直接参照を減らしたい

``` DollarFrancTest.java

    @Test
    public void testMultiplication(){
        Money five = Money.dollar(5);
        assertEquals(new Dollar(10),five.times(2));
        assertEquals(new Dollar(15),five.times(3));
    }

```

* Moneyにファクトリメソッドを導入し...

``` Money.java

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

```

* Moneyを抽象クラスにしてtimesメソッドを定義する

``` Money.java

abstract class Money {

    protected int amount;

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

    abstract  Money times(int multiplier);
}

```

* テストを修正する

``` DollarTest.java

    @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(new Franc(5).equals(new Franc(5)));
        assertFalse(new Franc(5).equals(new Franc(6)));
        assertFalse(new Franc(5).equals(Money.dollar(5)));
    }

```

* Francへの対応

``` FrancTest.java

    @Test
    public void testFrancMultiplication(){
        Money five = Money.franc(5);
        assertEquals(Money.franc(10),five.times(2));
        assertEquals(Money.franc(15),five.times(3));
    }

```

``` DollarTest.java

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

```

``` Money.java

abstract class Money {

    protected int amount;

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

    abstract  Money times(int multiplier);
}

```

## この章で行ったこと

1. 徐々に重複を取り除いた

1. ファクトリメソッドを導入し、サブクラスの存在をテストから分離した

# Part 1-9

## 通貨概念の導入

``` DollarFrancTest.java

    @Test
    public void testCurrency(){
        assertEquals("USD", Money.dollar(1).currency());
        assertEquals("CHF", Money.franc(1).currency());
    }

```
* currency()の実装

``` Money.java

    abstract String currency();

```

``` Dollar.java

class Dollar extends Money {

    private String currency;

    Dollar(int amount){
        this.amount = amount;
        currency = "USD";
    }

    String currency(){
        return currency;
    }

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

```

``` Franc.java

class Franc extends Money{

    private String currency;

    Franc(int amount){
        this.amount = amount;
        currency = "CHF";
    }

    String currency(){
        return currency;
    }

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

```

* サブクラス間の重複する実装をスーパークラスに移動

``` Money.java

    protected String currency;

    String currency(){
        return currency;
    }

```
``` Dollar.java

class Dollar extends Money {

    Dollar(int amount){
        this.amount = amount;
        currency = "USD";
    }

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

```

``` Franc.java

class Franc extends Money{

    Franc(int amount){
        this.amount = amount;
        currency = "CHF";
    }

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

```

* 通貨文字列をファクトリメソッドに移動し、コンストラクタを共通化したいが...

* コンストラクタに引数を追加すると

``` Franc.java

    Franc(int amount, String currency){
        this.amount = amount;
        this.currency = "CHF";
    }

```

* Francをnewしているところの修正が必要

``` Money.java

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


```

* ここはファクトリメソッド使うべきでは？

``` Franc.java

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

```

* timesがコンストラクタを使っていることに気づいたので、ファクトリメソッドを使うよう変更する

``` Franc.java

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

```

* ファクトリメソッドが文字列を渡せるようになる

``` Money.java

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


```

``` Franc.java

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

```

* 大きな変更を細かな変更に分割し、ミスを減らす
* Dollarに同じ変更を適用し、問題ないことを確認する

``` Money.java

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

```
``` Dollar.java

class Dollar extends Money {

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

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

```

* これでコンストラクタの実装が共通かできた
``` Money.java

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


```

``` Franc.java

    Franc(int amount, String currency){
        super(amount,currency);
    }

```

``` Dollar.java

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

```

## この章で行ったこと

1. コンストラクタの共通化

1. 小さなステップでリファクタリングした

``` DollarTest.java

public class DollarTest {

    @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 testCurrency(){
        assertEquals("USD", Money.dollar(1).currency());
        assertEquals("CHF", Money.franc(1).currency());
    }
}

```

``` FrancTest.java

public class FrancTest {

    @Test
    public void testFrancMultiplication(){
        Money five = Money.franc(5);
        assertEquals(Money.franc(10),five.times(2));
        assertEquals(Money.franc(15),five.times(3));
    }
}

```

``` Money.java

abstract class Money {

    protected int amount;

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

    abstract  Money times(int multiplier);

    protected String currency;

    String currency(){
        return currency;
    }

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

```

``` Dollar.java

class Dollar extends Money {

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

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

```
``` Franc.java

pclass Franc extends Money{

    Franc(int amount, String currency){
        super(amount,currency);
    }

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

```