Effective Java 項目1 「コンストラクタの代わりにstaticファクトリメソッドを検討する」

自分用メモなので雑です。


コンストラクタはこういうの
`public Human`の部分
（フィールド持たない場合は、何も書かなくてもデフォルトのコンストラクタが生成される）

```java
class Human {
    String name;
    public Human(String name) {
        this.name = name;
    }
}
```

コンストラクタを呼ぶ　＝　クラスのインスタンスを生成しても取得する

```java
Human human = new Human("yamada");
```

staticファクトリメソッドを用意してコンストラクタからはHumanを生成できないようにするとこうなる

```java
class Human {
    String name;
    
    // クライアントが、createHumanからしかHumanを作れないようコンストラクタはprivateにしている。
    private Human(String name) {
        this.name = name;
    }
    
   // staticなファクトリメソッド 
　　static Human createHuman(String name) {
        return new Human(name);
    }
}
```

### （コンストラクタではなく、）staticファクトリメソッドを使わせるメリット

- 1 名前がわかりやすい
- 2 呼び出しごとに新たなオブジェクトを作らなくて済むようになる
　呼び出しによって作られるオブジェクトの数なども簡単にコントロールできるようになる。シングルトンパターンがその一例。

```java
public class RegisterNote {
    
    private static RegisterNote registerNote = new RegisterNote();
    private RegisterNote(){}
    
    public static RegisterNote getInstance() {
        return registerNote;
    }    
}
```

上の例では、RegisterNoteがたった一つしか存在しえないことを保証している。



- 3 返す型を柔軟に選べる

例えば、`java.util.Collections`はCollection型のオブジェクトを返すファクトリメソッドがたくさん入っている。

```Java
public static final <T> List<T> emptyList() {
        return (List<T>) EMPTY_LIST;
    }
```
このemptyList()が返しているEMPTY_LISTは`EmptyList<E>`というクラスで、
EmptyList<E>は抽象クラスAbstractList<E>を継承し、AbstractList<E>はインターフェースList<E>を実装し、List<E>はインターフェースCollectionを拡張したものである。
慣習として、Hogeという名前のインターフェースのstaticファクトリメソッドはHogesというシングルトンのクラスに入れる。
（個人的に、これでライブラリの命名の規則についてかなり合点がいった。sついてるのとついてないのなんだろうって思ってたので）

でもあまり他の例が思いつかない、、、

- 4 引数によって、返すオブジェクトの型を自由に決められる。
例`EnumSet`クラス

enum型が64個以下で構成されている場合は、RegularEnumSetInstanceを返し、64個を超える場合は、JumboEnumSetを返す。
これはパフォーマンス上を考えてこうなっているだけで、特にクライアントには知ってほしくない。混乱を招くだけなので。
なので、staticファクトリメソッドの戻り値の型は単にEnumSetで、使う側は自分が作ったのがRegularEnumSetInstanceなのかそれともJumboEnumSetなのかを全く考えず、EnumSetに用意されたAPIを利用すればよい。

```java
public static <E extends Enum<E>> EnumSet<E> noneOf(Class<E> elementType) {
        Enum<?>[] universe = getUniverse(elementType);
        if (universe == null)
            throw new ClassCastException(elementType + " not an enum");

        if (universe.length <= 64)
            return new RegularEnumSet<>(elementType, universe);
        else
            return new JumboEnumSet<>(elementType, universe);
    }
```
- 5 返されるオブジェクトのクラスは、staticファクトリメソッドを書いている時点で存在する必要さえない
ちょっとよくわからなかった。Service Provider Interfaceについてちょっとドキュメント読んだが、なかなか難しい。
ただ、「リフレクションを使わずに」、とあるので、まだ宣言していないクラスも返すようにすることができる的なことだろう（）
そういう意味では4を拡大したような話だと思う。たぶん。
java.util.spi.CurrencyNameProviderについてちょっと見たが、おそらく通貨単位の略称（"JPY", "USD"など）をもとに、円マークやドル記号をStringとして返してくれるようなサービス（を作るのに？）使われている？あまりわかっていないが、、

## staticファクトリメソッドを使うことによって生まれる制約

- 1 コンストラクタがprivateだと、サブクラスが作れない

例：　下記は当然コンパイルエラーとなる。


```java
interface Writable {
    void write(String txt);
}

class Paper implements Writable{
    private Paper() {
        new Paper();
    }
    public static Paper createPaper() {
        return new Paper();
    }

    @Override
    public void write(String txt) {
        System.out.println("write to Paper.");
    }
}

class RichPaper extends Paper implements Writable {
    public RichPaper() {
        super();　// 親クラスPaperのコンストラクタはprivateなので、コンパイルエラーとなる
    }
}
```

しかし、これにより、継承よりもコンポジション（親クラスへの委譲によってメソッドを実装すること）を促すことのになるので、これはこれでよいとのこと。
（全然いい感じの例が思いつかなかった）

```java
class RichPaper implements Writable{
    private Paper paper;
    
    private RichPaper() {}
    
    RichPaper createRichPaper() {
        return new RichPaper();
    }

    @Override
    public void write(String txt) {
        paper.write(txt);
    }
}

```

- 2 staticファクトリメソッドだと、探すのが大変
確かに、これは自分も経験がある。とりあえずこのクラスを作りたい！っていうときに、コンストラクタがprivateで、「じゃあどこから作ればいいんだよ」とイラつく。

しかし、staticファクトリメソッドの一般的な命名規則を把握すればあんまり苦労しないかもなと思った。
下記のメソッドのニュアンスの違いは、本に載ってるので省略。

```java
from
of
valueOf
instance
getInstance
create
newInstance
//　ここからは、クラス名がHogeの場合
getHoge
newHoge
hoge
```

##　まとめ

それぞれのメリット、デメリットを意識して使い分ける。「staticファクトリメソッドにしたらどうかな？」と検討してみる。