[Java]privateジェネレータまたは列挙タイプで単一色調を保証


item3. privateジェネレータまたは列挙タイプで単一色調を保証


Effective Java学習

モノトーンとは?


1つのインスタンスしか作成できないクラス
クラスをモノトーンに設定すると、そのクライアントをテストするのは難しいです.
その生成方式は限られているため,モデルオブジェクトで代用することも困難であり,オブジェクトを動的に注入することも困難である.
テストは開発の核心ですが、テストコードを書くのが難しいのは大きな欠点です.
通常、単輪の作り方は2つのうちの1つです.
どちらの方法も、作成者をprivateとして非表示にし、インスタンスにアクセスする手段として共通の静的メンバーを使用します.

1.共通静的finalフィールド方式のモノトーン

public class Elvis {
    public static final Elvis INSTANCE = new Elvis();
    private Elvis() {...}

    public void leaveTheBuilding() {...}
privateジェネレータは、public static finalフィールドElvis.INSTANCEの初期化時に1回のみ呼び出される.
publicまたはprotected作成者がいないため、Elvisクラスの初期化時に作成されたインスタンスがクラス全体に1つしかないことを確認します.
ただし、例外として、アプリケーションAPI AccessibleObject.setAccessibleを使用してprivateジェネレータを呼び出すことができる.
これを防ぐには、ジェネレータを変更して、2番目のオブジェクトを作成するときに例外を放出します.
public class Elvis {
    public static final Elvis INSTANCE = new Elvis();
    private Elvis() {
        if(INSTANCE != null) throw new RuntimeException("Exceptions .... ");
    }

    public void leaveTheBuilding() {...}

2.静的工場化モノトーン


スタティックファクトリメソッドpublic staticメンバーが提供される.
public class Elvis {
    public static final Elvis INSTANCE = new Elvis();
    private Elvis() {...}
    
    public static Elvis getInstance() { return INSTANCE; }

    public void leaveTheBuilding() {...}
Elvis.getInstanceは、常に同じオブジェクトの参照を返し、システム全体でインスタンスが一意であることを保証することができる.
ただし、1に示すように、Replication APIによる例外も同様に適用される.
1番方式(public static final 필드 방식)の利点は、APIがクラスが単転であることを明確に示すことである.public staticfinalで、他のオブジェクトは絶対に参照できません.また、簡潔さのメリットも大きいです.
2番方式(정적 팩토리 방식)の利点は、APIを変更する必要がなく、非単一色調に変更できることである.一意のインスタンスを返すファクトリメソッドは、呼び出されたスレッドごとに異なるインスタンスを渡すことができます.
これに加えて、静的プラントを제네릭 싱글톤 팩토리に、静的プラント化の方法をSupplierに参照することもできる.
(Supplier:getメソッドで、任意のタイプのインタフェースを返すことができます.)
ex)
Supplier<Elvis> elvisSupplier = Elvis::getInstance;
Elvis elvis = elvisSupplier.get();
これらの利点を必要としない場合は、1番の方法(public static final 필드 방식)を選択することが望ましい.
しかしながら、上記の方法で作成した単一サイクルクラスをシリアル化するには、Serializableを実装するだけでは不十分であると主張する.すべてのインスタンスがtransientであることを宣言し、readResolutionメソッドを提供する必要があります.
private Obejct readResolve() {
	return INSTANCE;
}
そうでなければ、シリアルインスタンスを逆シリアル化するたびに、新しいインスタンスが生成されます.すなわち,偽のインスタンスが生成される.

3.列挙式モノトーン

public enum Elvis {
	INSTANCE; 

	public void leaveTheBuilding() { ... }
}
つまり、1つの要素のEnumタイプを宣言します.
1番方式と似ていますが、より簡潔にでき、追加の努力を必要とせずにシリアル化できます.また、複雑なシリアル化の場合であっても、第2の例の発生を完全に防止することができる.
ほとんどの場合、1つの要素のEnumタイプだけが単色調を生成する最良の方法です.
ただし、作成する単一トーンがEnum以外のクラスを継承する必要がある場合は、このメソッドは使用できません.