これは何?
Effective Java 第3版を読んで自分なりにかみ砕いた内容を記事に落としていきます。
良いコードを書くための選択肢の一つになれば最高なので、頑張ります。
※読み進める中で知識のアップデート等あれば都度更新いたします。
概要
クラスのインスタンスを得るために public のコンストラクタを作成するのではなく、
public の static ファクトリメソッドを作成するというもの
・例 (Booleanクラス)
boolean基本データ値をBooleanオブジェクト参照に変換している
public static Boolean valueOf(boolean b) {
return b ? Boolean.TRUE : Boolean.FALSE;
}
メリット
①コンストラクタと異なり名前を持つこと
クラスは特定のシグニチャ(※1)を持つコンストラクタを1つしか持てません。
→型の順序を変えて対応は可能ですが、コンストラクタを利用する際に間違ったコンストラクタを呼んでしまう可能性があります。
static ファクトリメソッドはメソッド名を持つため適切な名前を付けておけば読みやすく使いやすいコードになります。
良くない例
class Hoge {
public Hoge (String a, String b, String c, int d, int e) {
//処理を書く パターンA
}
public Hoge (int f, int g, String h, String i, String j) {
//処理を書く パターンB
}
良いない例
class Hoge {
public static A getパターンAのインスタンス(String a, String b, String c, int d, int e) {
//処理を書く パターンA
}
public static B getパターンBのインスタンス(int f, int g, String h, String i, String j) {
//処理を書く パターンB
}
※1.コンストラクタの引数の型やその順序などのこと
②呼び出しごとに新規オブジェクトを生成する必要がないこと
☑あらかじめ生成されたインスタンスを使用する
☑オブジェクトが生成されたときにインスタンスをキャッシュする
⇒重複したオブジェクトを生成しないようにします。
public final class Boolean implements java.io.Serializable {
public static final Boolean TRUE = new Boolean(true);
public static final Boolean FALSE = new Boolean(false);
/**
* 上で生成したTRUEとFALSE以外のインスタンスは生成しません
*/
public static Boolean valueOf(boolean b) {
return (b ? TRUE : FALSE);
}
static ファクトリメソッドが何度呼び出されても同じオブジェクトを返すため、どの時点でどんなインスタンスが存在するか把握できる。
このことを 「インスタンス制御されている」 といいます。
→クラスをシングルトンやインスタンス化不可能にできます。
③メソッドの戻り値として任意のサブタイプオブジェクトを返すことができる
インスタンス生成時に返すオブジェクトの型を柔軟に選択可能になります。
※ここについて、あまり理解できていないです
※TODO:改めて修正する
④returnされるオブジェクトのクラスを、入力パラメータの値に応じて呼び出しごとに変えられる
例えば、EnumSetクラスの場合
enum型が64個以下のときと、それより大きいときで返すサブクラスが違う。(RegularEnumSetとJumboEnumSet)
※あまりメリットが実感できていないが、使い分けられることでパフォーマンス上のメリットがあるそう
⑤returnされるオブジェクトのクラスは、staticファクトリメソッドを含むクラスが書かれた時点で存在する必要がない
※ここについて、あまり理解できていないです
※TODO:改めて修正する
#デメリット
##①publicあるいはprotectedのコンストラクタを持たないクラスのサブクラスを作成できない
このことから継承ではなく、コンポジションを使う必要がある。
→後の項で登場するのでその時改めて
##②staticファクトリメソッドを見つけるのが難しい
クラスに任意の名前を付与できるので、コンストラクタと比較して目立ちにくい
→命名規則を遵守することである程度回避できる