コンストラクターまたは列挙型を使用したシングルトン-第II章オブジェクトの作成と破棄-効果的なJavaスタディノート02

記事の内容は、Joshua Bloch-Effective Java(3rd)-2018.chm
BTW:シリアル化/シリアル化および逆シリアル化の概念、記事のシリアル化および逆シリアル化の概念については、次の記事を参照してください。
https://blog.csdn.net/qq_27093465/article/details/78544505

第2章

オブジェクトの作成と登録解除

項目3は、シングルトン属性にプライベートコンストラクターまたは列挙型を持たせる

プライベートコンストラクターまたは列挙型を使用してシングルトンプロパティを適用する
簡単に言うと、シングルトンは1回だけインスタンス化されるクラスです。通常、シングルトン表現は、関数などのステートレスオブジェクト、または本質的に唯一のシステムコンポーネントのいずれかです。
シングルトン(パターン)を実装する方法は2つあり、どちらもコンストラクターをプライベートに保つことと、パブリック静的メンバーをエクスポートして一意のインスタンスへのアクセスを提供することに基づいています。
メンバーは最終フィールドのメソッドです。

// Singleton with public final field
public class Elvis {
    public static final Elvis INSTANCE = new Elvis();
    private Elvis() { ... }

    public void leaveTheBuilding() { ... }
} 

プライベートコンストラクターは、パブリック静的最終フィールドElvis.INSTANCEインスタンスを初期化するために1回だけ呼び出されます。
パブリックコンストラクターまたは保護されたコンストラクターがないため、「単一のスプライト」ユニバースが保証されます。Elvisクラスが初期化されると、Elvisのインスタンスは1つだけになり、
クライアントクライアントはこれを変更できなくなりますが、
特別な注意事項が1つあります。 clientクライアントは、AccessibleObject.setAccessibleメソッドを使用して、プライベートコンストラクターを反射的に呼び出すことができます。
この攻撃から防御する必要がある場合は、コンストラクターを変更して、2番目のインスタンスの作成を求められたときに例外をスローすることができます。
パブリックメンバーは静的ファクトリメソッドです。

// Singleton with static factory
public class Elvis {
    private static final Elvis INSTANCE = new Elvis();
    private Elvis() { ... }
    public static Elvis getInstance() { return INSTANCE; }

    public void leaveTheBuilding() { ... }
}

Elvis.getInstanceへのすべての呼び出しは、同じオブジェクトへの参照を返し、他のElvisインスタンスを作成しません(前述の特別な手順と同じ)。

利点

パブリックフィールドメソッドの利点:
メインAPIはクラスを明確にします。これはシングルトンです。パブリック静的フィールドはfinalであるため、常に同じオブジェクト参照が含まれます
。2番目の利点は、
静的ファクトリが単純であるという利点があることです。メソッド:
1つは、APIを変更せずに、クラスがシングルトンであるかどうかについての考え方を柔軟に変更できることです。ファクトリメソッドは個別のインスタンスを返しますが、たとえば、各スレッドの個別のインスタンスを返すように変更されます。それは。通話ことを
第二の利点は、アプリケーションがそれを必要とする場合、あなたは一般的なシングルトンの工場を書くことができるということである。
最後の利点は、メソッドの参照が供給することができることである。
例えば、エルビス::インスタンスがあるサプライヤー

利点が関係しない限り、パブリックフィールドアプローチを使用する必要があります。

これらの2つのメソッドのいずれかを使用してシングルトンクラスをシリアライズ可能にするには、その宣言にシリアライズ可能な実装を追加するだけでは不十分です。
シングルトン保証を維持するには、すべてのインスタンスフィールドを一時的に宣言し、readResolveメソッドを提供する必要があります。
そうしないと、シリアル化されたインスタンスが逆シリアル化されるたびに、新しいインスタンスが作成されます。重要なことに、この例では、Elvisによる誤った目撃者になります。 [偽の目撃情報]
これを防ぐには、次のreadResolveメソッドをElvisクラスに追加します。

// readResolve method to preserve singleton property
private Object readResolve() {
     // Return the one true Elvis and let the garbage collector
     // take care of the Elvis impersonator.
    return INSTANCE;
} 

このメソッドはパブリックフィールドメソッドに似ていますが、より合理化され、無料のシリアル化メカニズムを提供し、複雑なシリアル化またはリフレクション攻撃に直面しても、複数のインスタンス化を防ぐことができるという確固たる保証を提供します。このアプローチは少し不自然に感じるかもしれませんが、通常、シングル要素の列挙がシングルトンを実装するための最良の方法です。シングルトンがEnum以外のスーパークラスを拡張する必要がある場合、このメソッドを使用できないことに注意してください(ただし、Enumはインターフェイスを実装するように宣言できます)。

3番目の方法

シングルトンを実装する3番目の方法は、単一要素[単一要素]列挙を宣言することです。

// Enum singleton - the preferred approach
public enum Elvis {
    INSTANCE;

    public void leaveTheBuilding() { ... }
}

元の

作者はこのセクションを理解していなかったので、メモの内容は元のテキストに残されています

項目3:プライベートコンストラクターまたは列挙型を使用してシングルトンプロパティを適用する
シングルトンは、1回だけインスタンス化されるクラスです[Gamma95]。シングルトンは通常、関数(アイテム24)などのステートレスオブジェクト、または本質的に一意のシステムコンポーネントのいずれかを表します。クラスをシングルトンにすると、その型として機能するインターフェイスを実装しない限り、モック実装をシングルトンに置き換えることができないため、クライアントのテストが困難になる可能性があります。

シングルトンを実装する一般的な方法は2つあります。どちらも、コンストラクターをプライベートに保ち、パブリック静的メンバーをエクスポートして、唯一のインスタンスへのアクセスを提供することに基づいています。1つのアプローチでは、メンバーは最後のフィールドです。

// Singleton with public final field
public class Elvis {
    public static final Elvis INSTANCE = new Elvis();
    private Elvis() { ... }

    public void leaveTheBuilding() { ... }
} 

プライベートコンストラクターは、パブリック静的最終フィールドElvis.INSTANCEを初期化するために1回だけ呼び出されます。パブリックコンストラクターまたは保護されたコンストラクターがないため、「モノエルビスティック」ユニバースが保証されます。Elvisクラスが初期化されると、Elvisインスタンスが1つだけ存在します。1つの注意点がありますが、クライアントがこれを変更することはできません。特権クライアントは、AccessibleObject.setAccessibleメソッドを使用してプライベートコンストラクターを反射的に呼び出すことができます(アイテム65)。この攻撃から防御する必要がある場合は、コンストラクターを変更して、2番目のインスタンスの作成を求められたときに例外をスローするようにします。

シングルトンを実装するための2番目のアプローチでは、パブリックメンバーは静的ファクトリメソッドです。

// Singleton with static factory
public class Elvis {
    private static final Elvis INSTANCE = new Elvis();
    private Elvis() { ... }
    public static Elvis getInstance() { return INSTANCE; }

    public void leaveTheBuilding() { ... }
} 

Elvis.getInstanceへのすべての呼び出しは同じオブジェクト参照を返し、他のElvisインスタンスは作成されません(前述の同じ警告があります)。

パブリックフィールドアプローチの主な利点は、APIがクラスがシングルトンであることを明確にすることです。パブリック静的フィールドはfinalであるため、常に同じオブジェクト参照が含まれます。2つ目の利点は、シンプルなことです。

静的ファクトリアプローチの利点の1つは、APIを変更せずに、クラスがシングルトンであるかどうかについての考えを柔軟に変更できることです。ファクトリメソッドは唯一のインスタンスを返しますが、たとえば、それを呼び出すスレッドごとに個別のインスタンスを返すように変更できます。2番目の利点は、アプリケーションで必要な場合にジェネリックシングルトンファクトリを記述できることです(アイテム30)。静的ファクトリを使用する最後の利点は、メソッド参照をサプライヤとして使用できることです。たとえば、Elvis :: instanceはSupplier <Elvisです。これらの利点の1つが関係しない限り、パブリックフィールドアプローチが望ましいです。

これらのアプローチのいずれかを使用するシングルトンクラスをシリアル化可能にするには(第12章)、宣言にSerializable実装を追加するだけでは不十分です。シングルトン保証を維持するには、すべてのインスタンスフィールドを一時的に宣言し、readResolveメソッドを提供します(アイテム89)。そうしないと、シリアル化されたインスタンスが逆シリアル化されるたびに、新しいインスタンスが作成され、この例の場合、偽のElvis目撃につながります。これが発生しないようにするには、次のreadResolveメソッドをElvisクラスに追加します。

// readResolve method to preserve singleton property
private Object readResolve() {
     // Return the one true Elvis and let the garbage collector
     // take care of the Elvis impersonator.
    return INSTANCE;
} 

シングルトンを実装する3番目の方法は、単一要素の列挙型を宣言することです。

// Enum singleton - the preferred approach
public enum Elvis {
    INSTANCE;

    public void leaveTheBuilding() { ... }
} 

このアプローチはパブリックフィールドアプローチに似ていますが、より簡潔で、シリアル化機構を無料で提供し、高度なシリアル化またはリフレクション攻撃に直面した場合でも、複数のインスタンス化に対する強力な保証を提供します。このアプローチは少し不自然に感じるかもしれませんが、シングル要素の列挙型がシングルトンを実装するための最良の方法であることがよくあります。シングルトンがEnum以外のスーパークラスを拡張する必要がある場合は、このアプローチを使用できないことに注意してください(ただし、列挙型を宣言してインターフェイスを実装することはできます)。

おすすめ

転載: blog.csdn.net/weixin_43596589/article/details/112552991