【Java】変更に強いコード - 値オブジェクト1（Value Object）

変更に強いコードを書くための考え方を学びます

#変更に強いコードの5つのポイント
* **1. 変数名は説明になるようにつけよう**
    * 入力、処理、出力の役割ごとに変数名を使う（説明用の変数を導入）
* **2. 目的ごとに変数を用意しよう**
    * 計算した結果に対して変数を用意して、**使いまわさない**
* **3. コードは意味のある段落に分けよう**
    * 入力、処理、出力に分ける
* **4. コードのまとまり（段落）をメソッドとして独立**させよう
    * 異なるクラスでの重複コードはなくそう
* **5. 狭い関心ごとに特化したクラス（ドメインオブジェクト）にしよう**
    * 凝集度up = あるクラスはある目的にのみ存在する
    * ex: 送料クラスの関心事は送料のみ


#小さなクラスでわかりやすく安全に
* 5つのポイントをおさえ、**特定の関心に特化した小さなクラス**を作る
    * メソッドは短く、クラスは小さく
    * クラスの可読性up、変更が簡単になる
* 継承で共通機能は親クラスへ
    * 派生クラスでは差分のspecificな部分のみ書くことで**最低限のコード**にする
* **値を扱う専用のクラス（値オブジェクト）**を作る

#値オブジェクト(Value Object)とは？
* データを使った業務ロジック：判断/加工/計算
* このデータの種類ごとに、値を扱う専用のクラスを作るということ。
    * 専用の型を用意(クラスやインターフェース)
    * 専用の型を使うと**不適切な値が混入するバグを防げる！**
    * 変更時にも、**クラスやインターフェース名を手掛かりに変更**できる
    * 値オブジェクトは非常に重要

##値オブジェクト実践
* 以下のコードをリファクタする時。。🤔

```java
int unitPrice = UNIT_PRICE;
int basePrice = unitPrice * quantity;
int basePriceWithTax = (int)(basePrice*TAX);
```

* **intは基本型なので使わないほうがいい**
    * ここで**値の種類ごとに専用の型を用意！**=値オブジェクト
    * valuesクラスにもつint 型のvalueを保存

```
Project Root
└─src
    └─ main
        └─ java  
            └─ Main
        └─ values
            └─ Price
            └─ Quantity
            └─ Tax

```

##Price / Quantity / Tax型を作る
 * 基本型ではなく**専用型**を用意し、intやfloatをPrice、Quantity、Taxに変更
 * getter(ここではgetValue())で値を返し、外から参照できるようにする
 * 処理中身はintなので計算中ではintになっているが、
 * 入力/処理/出力の**処理のみintで、クラスの中に閉じ込め、返すのはPrice型**
    * **→変更をここだけに閉じ込める**ことができる🌟


```java:Price.java
package values;

public class Price {
    private int value;
    public Price(int value){
        this.value = value;
    }
    public Price multiple(Quantity quantity){
        return new Price(this.value * quantity.getValue());
    }
    public Price getPriceWithTax(Tax tax){
        //tax.getValueはfloatなのでCast
        int priceWithTax = (int)(this.value * tax.getValue());
        //新しいオブジェクトを返す
        return new Price(priceWithTax);
    }

    public int getValue() {
        return value;
    }
}
```

```java:Quantity.java
package values;

public class Quantity {
    private int value;

    public Quantity (int value){
        this.value = value;
    }

    public int getValue() {
        return value;
    }
}


```

```java:Tax.java
package values;

public class Tax {
    private float value;

    public Tax (float value){
        this.value = value;
    }
    public float getValue() {
        return value;
    }
}


```



```java:Main.java
import values.Price;
import values.Quantity;
import values.Tax;

public class Main {

    private final static int UNIT_PRICE = 3000;
    private final static float TAX = 1.1f;

    public static void main(String[] args) {
       //コンストラクタで初期化
        var instance = new Main();
        var quantity = new Quantity(3);
        var totalCost = instance.getTotalCost(quantity);
        System.out.println(quantity.getValue());

        System.out.println("totalCost" + totalCost.getValue());
    }

    Price getTotalCost(Quantity quantity){
        Price unitPrice = new  Price(UNIT_PRICE);
        Price basePrice = unitPrice.multiple(quantity);
        System.out.println("basePrice: "+basePrice.getValue());
        Tax tax = new Tax(TAX);
        Price basePriceWithTax = basePrice.getPriceWithTax(tax);

/*リファクタ前
          int unitPrice = UNIT_PRICE;
          int basePrice = unitPrice * quantity;
          int basePriceWithTax = (int)(basePrice*TAX);
*/
        return basePriceWithTax;
    }

}

```

##関心事を外に閉じ込められてない例
* 上のMain.javaでの操作はこんな風に書くこともできる。が。。。。
* 値オブジェクトを使いながら、**実際の処理を外に書いてしまっている**🙀 （= Priceクラスを使う側で処理を書いている）
* なので、せっかく値オブジェクトを使っているのに、関心事を外に閉じ込められてないということになります。。

```java
//よくない例
Price unitPrice = new Price(UNIT_PRICE);
int basePrice = unitPrice.getValue() * quantity.getValue();
Tax tax = new Tax(TAX);
int basePriceWithTax = (int) (basePrice * tax.getValue());
```