![translation](https://cdn.durumis.com/common/trans.png)
Ceci est un post traduit par IA.
[Effective Java] Item 3. Garantir un singleton avec un constructeur privé ou un type énuméré
- Langue de rédaction : Coréen
- •
-
Pays de référence : Tous les pays
- •
- Technologies de l'information
Choisir la langue
Texte résumé par l'IA durumis
- Un singleton est une classe qui ne peut être instanciée qu'une seule fois, utilisée pour créer des objets sans état ou des composants système uniques.
- Il existe trois méthodes pour créer un singleton : utiliser un membre public statique qui est un champ final, fournir une méthode d'usine statique ou utiliser un type énuméré. La méthode utilisant un type énuméré est la plus souhaitable.
- Lors de la sérialisation d'une classe singleton, vous devez implémenter Serializable, déclarer tous les champs d'instance comme transient et redéfinir la méthode readResolve().
Singleton
Le concept de Singleton
Un singleton est une classe qui ne peut être instanciée qu'une seule fois. Un exemple typique de singleton est un objet sans état ou un composant système unique. Cependant, les classes singleton sont difficiles à tester si elles ne sont pas définies comme une interface et leur implémentation.
Comment créer un singleton
Méthode utilisant un membre public static final
public class Elvis {
public static final Elvis INSTANCE = new Elvis();
private Elvis() {
}
public void speak() {
System.out.println("elvis");
}
Le constructeur privé est appelé une seule fois lors de l'initialisation de l'instance Elvis, garantissant qu'il s'agit de la seule instance dans l'ensemble du système. Cependant, vous pouvez utiliser AccessibleObject.setAccessible() pour appeler le constructeur privé, mais cette méthode de modification par réflexion peut être empêchée en lançant une exception lorsque le deuxième objet est créé.
- Avantages
- Il est clair dans l'API que la classe est un singleton.
- Concis.
Méthode fournissant une méthode de fabrique statique publique
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");
}
Sauf modification par réflexion, cette méthode garantit également qu'il s'agit de la seule instance dans l'ensemble du système. Il suffit de rendre le champ privé et d'utiliser une méthode de fabrique statique pour renvoyer l'objet.
- Avantages
- Il est possible de modifier la classe pour qu'elle ne soit plus un singleton sans changer l'API.
- Par exemple, vous pouvez faire en sorte que la méthode de fabrique statique renvoie des instances différentes pour chaque thread.
- Vous pouvez le modifier en une méthode de fabrique de singleton générique si vous le souhaitez.
- Une référence de méthode de fabrique statique peut être utilisée comme fournisseur.
- Par exemple, vous pouvez utiliser Supplier<Elvis> au lieu de Elvis::getInstance.
- Il est possible de modifier la classe pour qu'elle ne soit plus un singleton sans changer l'API.
Si vous n'avez pas besoin d'utiliser les avantages ci-dessus, il est préférable d'utiliser la première méthode.
Méthode utilisant un type énuméré
public enum Elvis {
INSTANCE;
public void speak() {
System.out.println("elvis");
}
La méthode la plus souhaitable est d'utiliser un type énuméré. Cette méthode est plus sûre contre les attaques par réflexion et le code est plus propre que les deux méthodes précédentes. De plus, comme nous le verrons plus loin, les deux méthodes précédentes ont l'inconvénient de devoir ajouter du code supplémentaire lors de la sérialisation.
Cependant, il faut faire attention au fait que le singleton que vous souhaitez créer peut hériter d'une interface, mais pas d'une classe.
Points à prendre en compte lors de la sérialisation d'une classe singleton
Pour sérialiser une classe singleton créée à l'aide de la première ou de la deuxième méthode ci-dessus, vous devez non seulement implémenter Serializable, mais aussi déclarer tous les champs d'instance comme étant transitoires et redéfinir la méthode readResolve().
private Object readResolve throws ObjectStreamException {
return INSTANCE;