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

Effective Java 第3版を読んでの感想や独自の解説などを書きます。
第2版を昔から読んでいて、手元にあるので比較もしつつ記載します。

なお、第2版のタイトルは『コンストラクタの代わりにstaticファクトリーメソッドを検討する』となっていました。(細かいですがファクトリーとファクトリの違いがありました)

概要・感想

publicなコンストラクタを用意するより、staticなファクトリメソッドを用意しましょうという項目です。

イメージ的には

public class Hoge {
 private final String fuga;

 public Hoge(String fuga) {
  this.fuga = fuga;
 }
}

のような実装ではなく、

public class Hoge {
 private final String fuga;

 private Hoge(String fuga) {
  this.fuga = fuga;
 }

 public static Hoge of(String fuga) {
   return new Hoge(fuga);
 } 
}

のような実装をしようという感じです。

メリットについて

第3版でメリットとして記載されているのは

(第3版)
  1. 名前を持つこと
  2. 呼び出しごとにオブジェクトを生成する必要がないこと
  3. 任意のサブクラスのオブジェクトを返せること
  4. 返却されるオブジェクトのクラスを入力パラメータの値によって変えられること
  5. ファクトリメソッドが作成された時点で返却されるオブジェクトのクラスが存在する必要がないこと

となっています。第2版を確認してみましたが、第2版では以下のようになっていました。

(第2版)
  1. 名前を持つこと
  2. 呼び出しごとにオブジェクトを生成する必要がないこと
  3. 任意のサブクラスのオブジェクトを返せること
  4. パラメータ化された型のインスタンス生成の面倒さを低減すること

数的には増減がある様に見えますが、第2版では

(第2版)
  1. 任意のサブクラスのオブジェクトを返せること

の中に

(第3版)
  1. 任意のサブクラスのオブジェクトを返せること
  2. 返却されるオブジェクトのクラスを入力パラメータの値によって変えられること
  3. ファクトリメソッドが作成された時点で返却されるオブジェクトのクラスが存在する必要がないこと

の内容が書いてあるので、内容的には増えていないみたいです。
(1つのメリットとして記載していた内容を3つに分けて明確にした形だと思います)

また、

(第2版)
  1. パラメータ化された型のインスタンス生成の面倒さを低減すること

については第3版で消えていますが、これは第2版当時(java 6)は

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

の様にダイヤモンド構文を使うことができず、

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

と記載する必要があったところを

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

と書くことができるというメリットでした。

今(java 7 以降)はダイヤモンド構文があるので、おそらくメリットにならないということで削除されたんだと思います。

なお、第2版時点でも注釈(訳注)でダイヤモンド構文について触れているので、実質変更点はないと考えても良いと思います。

デメリットについて

デメリットとしては以下が記載されていました。

(第3版)
  1. publicかprotectedなコンストラクタを提供しない場合、サブクラスを作成することができない
  2. 利用者がファクトリメソッドを見つけることが難しい

第2版を改めて確認してみましたが、表現は多少変わっていましたが、内容的には同じでした。

個人的には一つ目のデメリットで困ったことは、ユニットでモック化したい時にできない(ことがある)程度で、あまり気にしないで良いレベルかなと思います。

二つ目のデメリットについても、一般的な命名規則に従った名前をつければ(そして利用者側が一般的な命名規則を知っていれば)特に困ることはないかなと思います。

ファクトリメソッドの名前について

ファクトリメソッドの名前は一般的な名前にしましょうという話も記載されています。

第2版では

(第2版)
  • valueOf
  • of
  • getInstance
  • newInstance
  • getType
  • newType

となっていましたが、第3版では

(第3版)
  • from
  • of
  • valueOf
  • instance もしくは getInstance
  • create もしくは newInstance
  • getType
  • newType
  • type

となっていました。 (なお、Typeは型になります)

第3版では具体例も書いてあって割と分かりやすくなっていました。

(第3版)
  • from … Date.from()
  • of … EnumSet.of()
  • valueOf … BigInteger.valueOf()
  • instance もしくは getInstance … StackWalker.getInstance()
  • create もしくは newInstance … Array.newInstance()
  • getType  … FileStore fs = Files.getFileStore()
  • newType … BufferedReader br = Files.newBufferedReader()
  • type … List<?> list = Collections.list()

それぞれ用途によって使い分けるものではありますが、個人的にはofとnewTypeを使うことが多いかなと思います。

createはあまり見たことなかったのですが、良さそうなので今後はこれも使っていこうと思います。

コメント

タイトルとURLをコピーしました