見出し画像

Effective Java(3rd) Item 1.1 Consider static factory methods instead of constructors


5P

クラスからインスタンスを得るためによくある方法はpublicなコンストラクタを与えるやり方である。実は方法はそれだけではない。クラスはpublicなstatic factory methodを与えることができる。これは単に、クラスのインスタンスを戻り値で返す静的メソッドである。ここでBoolean(booleanのboxed primitiveクラス)の簡単な例を見てみよう。このメソッドはbooleanのプリミティブな値をBooleanのオブジェクトの参照に変換している。

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

ここでstatic factory methodはデザインパターンのFactory Methodパターンとは別物であることに注意したい。ここでのstatic factory methodと同等のものはデザインパターンにはない。

クラスはpublicなコンストラクタの代わり、あるいはそれに加えてstatic factory methodsを与えてくれる。その際に利点と欠点がある。

コンストラクタと違って、static factory methodsの利点の1つは名前をつけることができることである。コンストラクタのパラメータ(引数)自体が、戻り値として返されるオブジェクトを記述できないなら、良い名前をつけられたstatic factoryは使いやすい読みやすい。

6P
 
例えば、おそらく素数であるBigIntegerを戻り値で返す、コンストラクタBigInteger(int, int, Random)よりBigInteger.probablePrimeと命名されたstatic factory methodの方がわかりやすいだろう(このメソッドはJava 4で追加された)。

クラスはあるシグネチャを持ったコンストラクタをひとつしか持てない。プログラマーは引数の型の順番を入れ替えれば、2つのコンストラクタを持てることを知っている。これは実に良くない考え方である。そのようなAPIのユーザはどっちのコンストラクタがどっちだが覚えられないだろうし、間違えるだろう。これらのコンストラクタを使ったコードを読む人々はクラスに関するドキュメントを読まずして内容を理解できないだろう。

名前があるので、static factory methodsなはこのような制約はない。同じシグネチャを持った複数のコンストラクタが必要なクラスは、代わりにその違いが明確になるように名付けられたstatic factory methodを使えば良い。

2つ目の利点は、コンストラクタと違って、呼び出される度に新たなオブジェクトを作る必要がないことである。これにより、immutableなクラス(Item 17)が未完成なインスタンスを使ったり、コンストラクタ生成時にインスタンスをキャッシュに格納することが可能になり、不必要に複製されたオブジェクトを生成しないようになる。Boolean.valueOf(boolean)メソッドはオブジェクトを生成しない。これはFlyweightパターンと似ている。これにより、等価なオブジェクトが頻繁にリクエストされたり、特に生成するのが大変な場合、パフォーマンスが劇的に改善される。

繰り返し呼び出される際に同じオブジェクトを返すというstatic factory methodsの特徴により、クラスがいつでもどんなインスタンスがあるか把握できるようになる。このようなクラスはinstance-controlledと呼ばれる。このように呼ぶ理由はいくつかある。Instance controlledなクラスはsingleton(Item 3)であり、かつnoninstantiable(Item 4)である。また、Instance controlledでimmutable valueなクラス(Item 17)の場合、二つの等価なインスタンスが存在しない。つまり、a==bの場合に限ってa.equals(b)である。これはFlyweightパターンの基礎である。Enum(Item 34)はこの保証を与える。

3番目の利点は、どんなサブタイプのオブジェクトも返すことができることである。これにより非常に柔軟に、返されるオブジェクトのクラスを選ぶことが出来るようになる。

この柔軟性の応用例として、APIがクラスをpublicにしなくてもオブジェクトを返せることが挙げられる。この際のhiding implementationなクラスにより、非常にコンパクトなAPIが出来上がる。このテクニックはinterface-based framework(Item 20)に含まれる。その際、インターフェイスはstatic factory methodsに戻り値として自然な型を与える。

この記事が気に入ったらサポートをしてみませんか?