web-dev-qa-db-fra.com

Comment s'assurer qu'il n'y a qu'une seule instance de classe dans la JVM?

Je développe un modèle de conception et je veux m'assurer qu'il ne s'agit que d'une instance d'une classe dans Java Virtual Machine, pour acheminer toutes les demandes de ressources par un point unique, mais je ne sais pas si c'est possible.

Je ne peux que penser à un moyen de compter les instances d'une classe et de détruire toutes les instances après sa création.

Est-ce une bonne approche? Si non, y a-t-il un autre moyen? 

16
Joe

Utilisez le singleton pattern. L'implémentation la plus simple consiste en un private constructor et une field pour conserver son résultat, ainsi qu'une méthode d'accesseur static avec un nom comme getInstance()

Le champ privé peut être affecté à partir d'un bloc d'initialiseur statique ou, plus simplement, à l'aide d'un initialiseur. La méthode getInstance() (qui doit être publique) renvoie alors simplement cette instance,

public class Singleton {
    private static Singleton instance;

    /**
     * A private Constructor prevents any other class from
     * instantiating.
     */
    private Singleton() {
        // nothing to do this time
    }

    /**
     * The Static initializer constructs the instance at class
     * loading time; this is to simulate a more involved
     * construction process (it it were really simple, you'd just
     * use an initializer)
     */
    static {
        instance = new Singleton();
    }

    /** Static 'instance' method */
    public static Singleton getInstance() {
        return instance;
    }

    // other methods protected by singleton-ness would be here...
    /** A simple demo method */
    public String demoMethod() {
        return "demo";
    }
}

Notez que la méthode d’utilisation de «lazy evaluation» dans la méthode getInstance() (préconisée dans Design Patterns) n’est pas nécessaire en Java, car Java utilise déjà «lazy Loading». Votre classe singleton n’obtiendra probablement pas. chargé à moins que sa getInstance()is soit appelée, il est donc inutile d'essayer de différer la construction du singleton tant que ce n'est pas nécessaire en ayant getInstance(), testez la variable singleton pour null et créez le singleton.

Utiliser cette classe est tout aussi simple: il suffit d’obtenir et de conserver la référence et d’appeler des méthodes dessus:

public class SingletonDemo {
    public static void main(String[] args) {
        Singleton tmp = Singleton.getInstance();
        tmp.demoMethod();
    }
}

Certains commentateurs estiment qu'un singleton devrait également fournir une méthode publique finale clone() qui lève simplement une exception, afin d'éviter les sous-classes qui «trichent» et clone() le singleton. Cependant, il est clair qu'une classe avec seulement un constructeur privé Ne peut pas être sous-classée, donc cette paranoïa ne semble pas être nécessaire.

27
Sufiyan Ghori

Vous voulez le modèle Singleton. Il y a une excellente discussion sur la manière de la mettre en œuvre correctement. Si vous faites cela correctement, il n'y aura jamais qu'une seule instance de la classe. 

En gros, vous allez créer une classe, conserver un seul objet instancié de cette classe au niveau statique et fournir un accesseur statique pour l'obtenir (getInstance() ou similaire). Rendez le constructeur final afin que les utilisateurs ne puissent pas créer leurs propres instances à l'improviste. Le lien ci-dessus contient de nombreux conseils judicieux sur la manière de procéder.

5
Todd

C'est le modèle Singleton bien connu: vous pouvez l'implémenter comme suit:

public class SingletonClass {

    //this field contains the single instance every initialized.
    private static final instance = new SingletonClass();

    //constructor *must* be private, otherwise other classes can make an instance as well
    private SingletonClass () {
        //initialize
    }

    //this is the method to obtain the single instance
    public static SingletonClass getInstance () {
        return instance;
    }

}

Vous appelez ensuite l'instance (comme si vous construisiez un non-singleton) avec:

SingletonClass.getInstance();

Mais en littérature, un Singleton est en général considéré comme une idée de conception mauvaise . Bien sûr, cela dépend toujours un peu de la situation, mais la plupart des programmeurs s’y opposent. Rien que pour le dire, ne tirez pas sur le messager ...

5
Willem Van Onsem

Il existe une école de pensée qui considère le modèle de Singleton comme un anti-modèle.

Si vous considérez une classe A dont vous souhaitez uniquement disposer, vous pouvez également définir une classe de constructeur ou une classe d’usine qui limite elle-même la création du nombre d’objets de la classe A et qui pourrait consister en un simple compteur. L'avantage est que la classe A n'a plus besoin de s'inquiéter de cela, elle se concentre sur son objectif réel. Chaque classe qui l'utilise n'a plus à s'inquiéter de son singleton (plus d'appels de getInstance ()).

5
Jool

Utilisez enum. En Java, enum est le seul véritable moyen de créer un singleton. Les constructeurs privés peuvent encore être appelés par réflexion.

Voir cette question StackOverflow pour plus de détails: Implémentation de Singleton avec un Enum (en Java)

Discussion: http://javarevisited.blogspot.com/2012/07/why-enum-singleton-are-better-in-Java.html

4
Vlad Lifliand

Je ne peux que penser à un moyen de compter les instances d'une classe et de détruire toutes les instances après sa création. Est-ce une bonne approche? Si non, y a-t-il un autre moyen? 

L'approche technique correcte consiste à déclarer tous les constructeurs de la classe en tant que private, de sorte que des instances de la classe ne puissent être créées que par la classe elle-même. Ensuite, vous codez la classe uniquement pour créer une seule instance.

Autres réponses montrent certaines des manières de mettre en œuvre cela, selon le modèle de conception "Singleton". Cependant, la mise en œuvre d’un singleton comme celui-ci présente certains inconvénients, notamment qu’il est beaucoup plus difficile d’écrire des tests unitaires.

3
Stephen C

Je préfère la classe singleton paresseuse, qui remplace la méthode readResolve .

Pour les classes Serializable et Externalizable, la méthode readResolve permet à une classe de remplacer/résoudre l'objet lu dans le flux avant de le retourner à l'appelant. En implémentant la méthode readResolve, une classe peut contrôler directement les types et instances de ses propres instances en cours de désérialisation.

Singleton paresseux avec /Initialization-on-demand_holder_idiom :

public final class  LazySingleton {
    private LazySingleton() {}
    public static LazySingleton getInstance() {
        return LazyHolder.INSTANCE;
    }
    private static class LazyHolder {
        private static final LazySingleton INSTANCE = new LazySingleton();
    }
    private Object readResolve()  {
        return LazyHolder.INSTANCE;
    }
}

Notes clés:

  1. Le mot clé final interdit l'extension de cette classe en sous-classant
  2. Le constructeur private interdit la création d'objet direct avec l'opérateur new dans les classes d'appelant
  3. readResolve interdit la création de plusieurs instances de la classe lors de la désérialisation des objets 
2
Ravindra babu

Pour cela, vous devez utiliser un motif singleton, je publie simplement un code de démonstration qui pourra vous être utile.

E.g: Si je veux un seul objet pour cette classe Connect:

public final class Connect {

    private Connect() {}

    private volatile static Connect connect = null;

    public static Connect getinstance() {
        if(connect == null) {
            synchronized (Connect.class) {
                connect = new Connect();
            }
        }
        return connect;
    }
}

Ici, le constructeur est privé, donc personne ne peut utiliser le mot clé new pour créer une nouvelle instance.

1
Chandan Rajput
class A{
    private A(){

    }
    public static A creator(A obj){
        A ob=new A();
        return ob;
    }
    void test(){
        System.out.println("The method is called");
    }
}

class Demo{
    public static void main(String[] args){
        A ob=null;
        ob=A.creator(ob);
        ob.test();
    }
}
0
Alex Vipul Verma