Suche…


Einführung

Ein Singleton ist eine Klasse, die immer nur eine Instanz hat. Weitere Informationen zum Singleton- Entwurfsmuster finden Sie im Thema Singleton im Design Patterns- Tag.

Enum Singleton

Java SE 5
public enum Singleton {
    INSTANCE;

    public void execute (String arg) {
        // Perform operation here 
    }
}

Enums haben private Konstruktoren, sind endgültig und bieten geeignete Serialisierungsmaschinen. Sie sind auch sehr knapp und fadensicher initialisiert.

Die JVM bietet die Garantie, dass die Aufzählungswerte nicht mehr als jeweils einmal instanziiert werden, was dem Aufzählungszeichen eine enorme Abwehr gegen Reflexionsangriffe gibt.

Wobei das Enumerationsmuster nicht schützt, wenn andere Entwickler dem Quellcode physikalisch mehr Elemente hinzufügen. Wenn Sie diesen Implementierungsstil für Ihre Singletons wählen, müssen Sie daher unbedingt eindeutig dokumentieren, dass diesen Aufzählungen keine neuen Werte hinzugefügt werden sollen.

Dies ist die empfohlene Methode zum Implementieren des Singleton-Musters, wie von Joshua Bloch in Effective Java erläutert .

Fadensicheres Singleton mit doppeltem Karo-Verschluss

Dieser Singleton-Typ ist threadsicher und verhindert unnötiges Sperren, nachdem die Singleton-Instanz erstellt wurde.

Java SE 5
public class MySingleton {

    // instance of class
    private static volatile MySingleton instance = null;

    // Private constructor
    private MySingleton() {
        // Some code for constructing object
    }

    public static MySingleton getInstance() {
        MySingleton result = instance;
        
        //If the instance already exists, no locking is necessary
        if(result == null) {
            //The singleton instance doesn't exist, lock and check again
            synchronized(MySingleton.class) {
                result = instance;
                if(result == null) {
                    instance = result = new MySingleton();
                }
            }
        }
        return result;
    }
}

Es muss hervorgehoben werden - in Versionen vor Java SE 5 ist die obige Implementierung falsch und sollte vermieden werden. Es ist nicht möglich, doppelt geprüftes Sperren vor Java 5 korrekt in Java zu implementieren.

Singleton ohne Enum (eifrige Initialisierung)

public class Singleton {    

    private static final Singleton INSTANCE = new Singleton();

    private Singleton() {}

    public static Singleton getInstance() {
        return INSTANCE;
    }
}

Es kann argumentiert werden , dass dieses Beispiel wirksam faul Initialisierung ist. Abschnitt 12.4.1 der Java-Sprachspezifikation lautet:

Eine Klasse oder ein Schnittstellentyp T wird unmittelbar vor dem ersten Auftreten eines der folgenden Ereignisse initialisiert:

  • T ist eine Klasse und eine Instanz von T wird erstellt
  • T ist eine Klasse und eine von T deklarierte statische Methode wird aufgerufen
  • Ein durch T deklariertes statisches Feld wird zugewiesen
  • Ein von T deklariertes statisches Feld wird verwendet und das Feld ist keine konstante Variable
  • T ist eine Klasse der obersten Ebene, und eine in T eingebettete Assert-Anweisung wird ausgeführt.

Solange es keine anderen statischen Felder oder statischen Methoden in der Klasse gibt, wird die Singleton Instanz daher erst initialisiert, wenn die Methode getInstance() zum ersten Mal aufgerufen wird.

Fadensichere Lazy-Initialisierung mit der Holder-Klasse | Bill Pugh Singleton Implementierung

public class Singleton {
    private static class InstanceHolder {
        static final Singleton INSTANCE = new Singleton();
    }

    public static Singleton getInstance() {
        return InstanceHolder.INSTANCE;
    }

    private Singleton() {}
}

Dies initialisiert die INSTANCE Variable beim ersten Aufruf von Singleton.getInstance() , wobei die Thread-Sicherheitsgarantien der Sprache für die statische Initialisierung genutzt werden, ohne dass eine zusätzliche Synchronisierung erforderlich ist.

Diese Implementierung wird auch als Bill Pugh Singleton Pattern bezeichnet. [Wiki]

Singleton erweitern (Singleton-Vererbung)

In diesem Beispiel stellt die Singleton getMessage() die getMessage() Methode getMessage() , die "Hello world!" getMessage() Botschaft.

Die Unterklassen UppercaseSingleton und LowercaseSingleton überschreiben die getMessage () -Methode, um die entsprechende Darstellung der Nachricht bereitzustellen.

//Yeah, we'll need reflection to pull this off.
import java.lang.reflect.*;

/*
Enumeration that represents possible classes of singleton instance.
If unknown, we'll go with base class - Singleton.
*/
enum SingletonKind {
    UNKNOWN,
    LOWERCASE,
    UPPERCASE
}

//Base class
class Singleton{

    /*
    Extended classes has to be private inner classes, to prevent extending them in 
    uncontrolled manner.
     */
    private class UppercaseSingleton extends Singleton {

        private UppercaseSingleton(){
            super();
        }

        @Override
        public String getMessage() {
            return super.getMessage().toUpperCase();
        }
    }

    //Another extended class.
    private class LowercaseSingleton extends Singleton
    {
        private LowercaseSingleton(){
            super();
        }

        @Override
        public String getMessage() {
            return super.getMessage().toLowerCase();
        }
    }

    //Applying Singleton pattern
    private static SingletonKind kind = SingletonKind.UNKNOWN;

    private static Singleton instance;

    /*
    By using this method prior to getInstance() method, you effectively change the
    type of singleton instance to be created.
     */
    public static void setKind(SingletonKind kind) {
        Singleton.kind = kind;
    }

    /*
    If needed, getInstance() creates instance appropriate class, based on value of
    singletonKind field.
     */
    public static Singleton getInstance() 
        throws  NoSuchMethodException, 
                IllegalAccessException, 
                InvocationTargetException, 
                InstantiationException {

        if(instance==null){
            synchronized (Singleton.class){
                if(instance==null){
                    Singleton singleton = new Singleton();
                    switch (kind){
                        case UNKNOWN:

                            instance = singleton;
                            break;

                        case LOWERCASE:

                            /*
                             I can't use simple

                             instance = new LowercaseSingleton();

                             because java compiler won't allow me to use
                             constructor of inner class in static context,
                             so I use reflection API instead.

                             To be able to access inner class by reflection API,
                             I have to create instance of outer class first.
                             Therefore, in this implementation, Singleton cannot be
                             abstract class.
                             */

                            //Get the constructor of inner class.
                            Constructor<LowercaseSingleton> lcConstructor =
                                    LowercaseSingleton.class.getDeclaredConstructor(Singleton.class);

                            //The constructor is private, so I have to make it accessible.
                            lcConstructor.setAccessible(true);

                            // Use the constructor to create instance.
                            instance = lcConstructor.newInstance(singleton);

                            break;

                        case UPPERCASE:

                            //Same goes here, just with different type
                            Constructor<UppercaseSingleton> ucConstructor =
                                    UppercaseSingleton.class.getDeclaredConstructor(Singleton.class);
                            ucConstructor.setAccessible(true);
                            instance = ucConstructor.newInstance(singleton);
                    }
                }
            }
        }
        return instance;
    }

    //Singletons state that is to be used by subclasses
    protected String message;

    //Private constructor prevents external instantiation.
    private Singleton()
    {
        message = "Hello world!";
    }

    //Singleton's API. Implementation can be overwritten by subclasses.
    public String getMessage() {
        return message;
    }
}

//Just a small test program
public class ExtendingSingletonExample {

    public static void main(String args[]){

        //just uncomment one of following lines to change singleton class

        //Singleton.setKind(SingletonKind.UPPERCASE);
        //Singleton.setKind(SingletonKind.LOWERCASE);

        Singleton singleton = null;
        try {
            singleton = Singleton.getInstance();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        }
        System.out.println(singleton.getMessage());
    }
}


Modified text is an extract of the original Stack Overflow Documentation
Lizenziert unter CC BY-SA 3.0
Nicht angeschlossen an Stack Overflow