![translation](https://cdn.durumis.com/common/trans.png)
Questo è un post tradotto da IA.
[Effective Java] Elemento 3. Garantisci il singleton con un costruttore privato o un tipo di enumerazione
- Lingua di scrittura: Coreana
- •
-
Paese di riferimento: Tutti i paesi
- •
- Tecnologia dell'informazione
Seleziona la lingua
Testo riassunto dall'intelligenza artificiale durumis
- Un singleton è una classe che può creare solo un'istanza e viene utilizzata per creare oggetti senza stato o componenti di sistema univoci.
- Esistono modi per creare singleton come avere un membro statico pubblico come campo finale, fornire un metodo di fabbrica statico o utilizzare un tipo di enumerazione, e l'utilizzo di un tipo di enumerazione è il metodo migliore.
- Quando si serializza una classe singleton, è necessario implementare Serializable, dichiarare tutti i campi di istanza come transitori e sovrascrivere il metodo readResolve().
Singleton
Il concetto di Singleton
Un singleton è una classe che può creare solo un'istanza. Un esempio tipico di singleton è un oggetto senza stato o un componente di sistema univoco. Tuttavia, le classi singleton sono difficili da testare a meno che il loro tipo non sia definito come interfaccia e la sua implementazione sia definita separatamente.
Come creare un singleton
Metodo con campo final static public
public class Elvis {
public static final Elvis INSTANCE = new Elvis();
private Elvis() {
}
public void speak() {
System.out.println("elvis");
}
Il costruttore privato viene chiamato solo una volta quando si inizializza l'istanza di Elvis, garantendo che sia l'unica istanza nell'intero sistema. Tuttavia, è possibile chiamare il costruttore privato utilizzando AccessibleObject.setAccessible(), ma questo metodo di modifica mediante riflessione può essere prevenuto generando un'eccezione quando viene creato il secondo oggetto.
- Vantaggi
- È chiaro dall'API che la classe è un singleton.
- È conciso.
Metodo che fornisce un metodo statico di fabbrica pubblico
public class Elvis {
private static final Elvis INSTANCE = new Elvis();
private Elvis() {
}
public static Elvis getInstance() {
return INSTANCE;
}
public void speak() {
System.out.println("elvis");
}
Oltre alla modifica tramite riflessione, questo metodo garantisce anche che esista una sola istanza nell'intero sistema. Il campo viene semplicemente reso privato e il metodo statico di fabbrica viene utilizzato per restituire l'oggetto.
- Vantaggi
- È possibile modificare il singleton in modo che non sia più un
singleton senza modificare l'API.
- Ad esempio, il metodo statico di fabbrica può restituire istanze diverse per ogni thread che lo chiama.
- È possibile convertirlo in un metodo di fabbrica singleton generico se necessario.
- È possibile utilizzare il riferimento del metodo del metodo statico
di fabbrica come fornitore.
- Ad esempio, è possibile utilizzarlo come Supplier<Elvis> invece di Elvis::getInstance.
- È possibile modificare il singleton in modo che non sia più un
singleton senza modificare l'API.
Se non hai bisogno di utilizzare i vantaggi sopra menzionati, è meglio utilizzare il primo metodo.
Metodo che utilizza un tipo enumerato
public enum Elvis {
INSTANCE;
public void speak() {
System.out.println("elvis");
}
Il modo più desiderabile è quello di utilizzare un tipo enumerato. Questo metodo è più sicuro degli attacchi di riflessione e il codice è più pulito rispetto ai due metodi precedenti. Inoltre, come descritto di seguito, i due metodi precedenti hanno lo svantaggio di richiedere codice aggiuntivo per la serializzazione.
Tuttavia, è necessario prestare attenzione al fatto che se si desidera che il singleton ereditato ereditare un'interfaccia, è possibile ereditare un'interfaccia, ma non una classe.
Punti da considerare quando si serializza una classe singleton
Se si desidera serializzare una classe singleton creata utilizzando il primo o il secondo metodo sopra menzionato, è necessario dichiarare tutti i campi di istanza come transitori e sovrascrivere il metodo readResolve() oltre a implementare Serializable.
private Object readResolve throws ObjectStreamException {
return INSTANCE;