【Effective Javaを読む】　第２章　項目１　『コンストラクタの代わりにstaticファクトリーメソッドを検討する』

#はじめに

Javaの理解を深めるならこれを読めということで、Effective Javaを自分なりに解釈しながら読んでいこうと思います。
読んでるのは積読していた第２版です。
https://www.amazon.co.jp/EFFECTIVE-JAVA-Java-Joshua-Bloch/dp/4621066056/ref=pd_sbs_14_3/355-5139262-7829161?_encoding=UTF8&pd_rd_i=4621066056&pd_rd_r=ac861412-beae-43a8-872a-8b853aa69980&pd_rd_w=oIuWA&pd_rd_wg=nhmjU&pf_rd_p=7642417c-6494-4d06-a2b0-fcb0e0b3c563&pf_rd_r=HAEC02ASTQVJ4SPSM92Q&psc=1&refRID=HAEC02ASTQVJ4SPSM92Q

#コンストラクタの代わりにstaticファクトリーメソッドを検討する
今までコンストラクタを使って実装していた処理を、staticファクトリーメソッドに置き換えてみたら色々嬉しいことあるんじゃないですかねっていってる節

##サンプルコード

```java:例１

public static Boolean valueOf(boolean b){
    return b ? Boolean.TRUE : Boolean.FALSE;
}
```

```java:例２

//サービスプロバイダーフレームワーク
public interface Service{
    //サービス固有のメソッドをここに
}

//サービスプロバイダーインターフェース
public interface Provider{
    Service newService();
}

//サービス登録とアクセスのためのインスタンス化不可能クラス
public class Service{
    private Service(){} //インスタンス化を抑制（項目４）

    //サービス名をサービスと対応づける
    private static final Map<String, Provider> providers = new ConcurrentHashMap<String, Provider>();
    public static final String DEFAULT_PROVIDER_NAME = "<def>";

    //プロバイダー登録API
    public static void registerDefaultProvider(Provider p){
        registerProvider(DEFAULT_PROVIDER_NAME,p);
    }
    public static void registerProvider(String name,Provider p){
        providers.put(name,p);
    }

    //サービスアクセスAPI
    public static Service newInstance(){
        return newInstance(DEFAULT_PROVIDER_NAME);
    }
    public static Service newInstance(String name){
        Provider p = providers.get(name);
        if (p == null)
            throw new IllegalArgumentException(
                    "Nn provider registered with name:" + name
            );
        return p.newService();
    }
    
}

```

##用語集
###コンストラクタ
・コンストラクタとは、クラスのインスタンスを作成するときに実行される処理のこと

```java
SampleClass instanceA = new SampleClass();
```
↑newの後ろのSampleClasss()の記述がコンストラクタの呼び出し

・コンストラクタの書き方：クラス名と同じにする

```java

public class SampleClass {
  //コンストラクタ
  public SampleClass(){
    System.out.println("コンストラクタだよー");
  }
}
```
↑これでnewした時に「コンストラクタだよー」が標準出力される

・メソッドと違ってコンストラクタは値を返さない（returnを書くとエラーになる）

###static
・インスタンスに依存しないメソッドや変数を作るための修飾詞

###staticファクトリーメソッド
・staticファクトリーメソッドとは、オブジェクトを返す単なるstaticのメソッドのこと
・例１ではboolean基本データ値（b）をBooleanオブジェクトに変換している

###デザインパターンのファクトリーメソッド
・名前が似てるけどstaticファクトリーメソッドとは別物
・ここでは説明は割愛

###インターフェース
・インターフェースとは、クラス内にあるメソッドの具体的な処理は書かずに「変数」または「メソッドの型」を記述したもの
・「すべてのメソッドが抽象メソッドであること」「基本的にフィールドを1つも持っていないこと」が条件
・処理内容を具体的に書いていないため、使いたいときに処理内容を実装すればい良いので、将来的に処理の変更が起こりうる場合などに便利（細かいところを後回しにできる）



##staticファクトリーメソッドの４つの長所と２つの短所

###長所１　コンストラクタと異なり名前を持つ
・コンストラクタはnewすると勝手に実行されちゃうけど、staticファクトリーメソッドならいい感じの名前が付けられるので可読性があがる

例えば確率的素数（probable prime）であるBigIntegerを返す処理があるとして、

-コンストラクタでの書き方

```java
BigInteger(int, int, Random)
```
-staticファクトリーメソッドでの書き方

```java
BigInteger.probablePrime
```
…どっちがわかり易い？

###長所２　コンストラクタと異なりメソッドが呼び出されるごとに新たなオブジェクトを生成する必要がない

・当たり前だけど、staticなので何にもインスタンス化していない
　コンストラクタを呼び出すためにはnewしなくちゃいけない
・不必要に新しいオブジェクトをたくさん作っちゃうのはあんまりよろしくないよねって話

###長所３　コンストラクタと異なりメソッドの戻り値型の任意のサブタイプのオブジェクトでも返すことができる

・コンストラクタは戻り値を返さないものだけど、staticファクトリーメソッドはあくまでメソッドなのでreturnすることができるので柔軟性がある
・例２のようなサービスプロバイダーフレームワーク（中身を隠蔽してAPIとして使ってもらう）もつくれちゃうぜ

###長所４　パラメータ化された型のインスタンス生成の面倒さを低減する

・冗長な書き方を簡略化できる
例えばコンストラクタだとこう書かなきゃいけなかったものが

```java
Map<String, List<String>> m =
  new HashMap<String, List<String>>();
```

staticファクトリーメソッドだとこう書ける

```java
Map<String, List<String>> m = HashMap.newInstance();
```

簡潔ですよね

もちろん裏ではstaticファクトリーメソッドをこんな感じで実装している

```java
public static <K, V> HashMap<K, V> newInstance() {
  return new HashMap<K. V>;
}
```

※P.S. Java7からは型類推をしてくれるのでstaticファクトリーメソッドは書かなくてもいい

###短所１　publicあるいはprotectedのコンストラクタをもたないクラスのサブクラスを作れない

###短所２　それらが容易に他のstaticメソッドと区別がつかない
・コンストラクタと違ってJavadocがうまく認識してくれない


##staticファクトリーメソッドの一般的な名前

|名前|役割
|---|---
|valueOf|パラメータと同じ値を持つインスタンスを返す。実質的に型変換メソッドである。
|of|valueOfの代替。より簡潔にしたもの。
|getInstance|パラメータで指定されたインスタンスを返すが、同じ値を持つとは言えない。シングルトンの場合には、getInstanceは何も引数を取らず、その唯一のインスタンスが返される。
|newInstance|getInstanceに似ているが、newInstanceは返される個々のインスタンスは、すべて別々のインスタンスである点が異なる。
|getType|getInstanceに似ているが、ファクトリーメソッドが対象のクラスと異なるクラスにある場合に使用され。Typeはファクトリーメソッドから返されるオブジェクトの型を示す。
|newType|newInstanceに似ているが、ファクトリーメソッドが対象のクラスと異なるクラスにある場合に使用される。Typeはファクトリーメソッドから返されるオブジェクトの型を示す。

#続く
【Effective Javaを読む】　第２章　項目２　『数多くのコンストラクタパラメータに直面した時にはビルダーを検討する』
https://qiita.com/Natsukii/items/eb8fec0d8cae567f6647