読者です 読者をやめる 読者になる 読者になる

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

オブジェクトを生成するため、public コンストラクタの代わりに static ファクトリーメソッドを提供するべき。

static ファクトリーメソッドとはクラスのインスタンスを返す単なる static メソッド。GoFデザインパターンで議論される「ファクトリーメソッド」とは異なるので注意が必要。

例えば、Java の Boolean で実装されている static ファクトリーメソッドは以下のようになっている。

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

static ファクトリーメソッドを用いる長所はたくさんある。

  • コンストラクタと異なり、名前を明示的にすることが出来る
    • コンストラクタはかならずクラス名と一致してしまう
  • 特定の引数列を持つコンストラクタは一種類しか持てないが、static コンストラクタは名前を変えることで複数持つことが可能になる
  • メソッドが呼び出されるごとにオブジェクトを再生成しなくてもよい
    • 前述の valueOf はこのパターン。GoFFlyweight パターンに相当する
    • シングルトン(項目3)、インスタンス化不可能(項目4)、不変クラス(項目15)などのインスタンスを制御下におく必要があるパターンへ応用できる
  • メソッドの戻り型として、任意のサブタイプオブジェクトを返せる
    • 返すオブジェクトのクラスを public にする必要がなく、実装クラスを隠蔽することができる 
    • インタフェースは static メソッドを持てない。その場合は、Types 名のインスタンス化不可能クラス(項目4)にいれることが多い。
    • java.util.Collection の実装は 32 個あるが、ファクトリーメソッドによってほとんどの実装は隠蔽されている。
    • EnumSet がその例。enum 型の値の個数によって EnumSet のファクトリーメソッドは返す実装を RegularEnumSet と JumboEnumSet とで分けている 1
  • パラメータ化された型のインスタンス生成の面倒さを低減する
    • Java 7 からは ダイヤモンド構文が使えるのでこの長所はもう意味がない

もちろん、短所もある。

  • public あるいは protected のコンストラクタを持たないクラスのサブクラスは static ファクトリーメソッドでは作れない
  • 他の static メソッドと区別がつかない
  • 上記の理由から以下の様な命名規則がある
    • valueOf(): パラメータと同じ値を持つインスタンスを返す。実質的には型変換メソッド。
    • of(): valueOf に対する簡潔な代替
    • getInstance(): パラメータで指定されたインスタンスを返す。なお、同じ値を持つとは限らない(例:java.security.SecureRandom)
    • newInstance(): getInstance に似ているが、個々のインスタンスはすべて別のインスタンス
    • getType: getInstance に似ているが、ファクトリーメソッドが対象のクラスと異なるクラスにある場合に利用される。Type は返されるオブジェクトの型の名前。
    • newType: newInstance に似ているが、ファクトリーメソッドが対象のクラスと異なるクラスにある場合に利用される。Type は返されるオブジェクトの型の名前。

通常のコンストラクタと static ファクトリーメソッド。それぞれ利用方法があるが、大抵の場合は Static ファクトリーメソッドの方が好ましい。

感想とか

本当は2章まるごと1記事にしようと思ったが、長くなるし、タスクは細かくしたほうがいろいろと管理しやすいのと、達成感を味わう頻度を高くしたほうが継続力が高まるので、項目ごとに1記事にすることにした。

前回の Effective JavaScript シリーズでは感想とかほとんど書かなかったけど、それぞれの項目に対してどう考えたかが重要な気もしたので記録しておくことにした。

static ファクトリーメソッドは実際 java.util でけっこう使われてるようだし、今まで関わったプロジェクトでも目にしたので重要なイディオムだと思う。

実装クラスは隠蔽して、static ファクトリーメソッド使うみたいなのはオブジェクト指向っぽい感じがして好き。 あと感想といえば「そういえば Scala だと Object の apply があるなー」とかか。

なんか途中でサービスプロバイダーフレームワークの説明があったけど、まあいらないかと思ってはしょった。

EFFECTIVE JAVA 第2版 (The Java Series)

EFFECTIVE JAVA 第2版 (The Java Series)

Kindle 版はこちら(ただし英語)

Effective Java: A Programming Language Guide (Java Series)

Effective Java: A Programming Language Guide (Java Series)