CodeGym /Java-Blog /Random-DE /Muster und Singleton in Java
Autor
Jesse Haniel
Lead Software Architect at Tribunal de Justiça da Paraíba

Muster und Singleton in Java

Veröffentlicht in der Gruppe Random-DE
Dieser Artikel richtet sich an alle, die zum ersten Mal mit dem Konzept von Designmustern in Berührung kommen, den Begriff Singleton gehört haben oder das Singleton-Muster irgendwie implementiert haben, aber nicht verstanden haben, was passiert. Willkommen! CodeGym-Schüler begegnen Designmustern zum ersten Mal auf Level 15, als der Kapitän sie unerwartet auffordert, ihr Verständnis durch die Implementierung des Java-Singleton-Musters mit Lazy-Implementierung zu „festigen“. Schüler , die zum ersten Mal vom Singleton- Muster hören, haben sofort viele Fragen: Was in aller Welt ist ein Entwurfsmuster? Warum brauchen wir es? Was ist ein Singleton ? Und schließlich: Was ist eine verzögerte Implementierung? Beantworten wir diese Fragen der Reihe nach.

Was in aller Welt ist ein Designmuster?

Ich glaube, dass ein wenig Geschichte nötig ist, um diese Frage mit dem besten Verständnis zu beantworten. Es gibt vier berühmte Programmierautoren (Erich Gamma, John Vlissides, Ralph Johnson und Richard Helm), die eine interessante Idee hatten. Sie stellten fest, dass sie bei der Softwareentwicklung oft ungefähr die gleichen Probleme lösen und Code schreiben mussten, der auf die gleiche Weise strukturiert war. Deshalb beschlossen sie, typische Muster zu beschreiben, die häufig in der objektorientierten Programmierung verwendet werden müssen. Ihr Buch wurde 1994 unter dem Titel Design Patterns: Elements of Reusable Object-Oriented Software veröffentlicht. Der Name des Buches erwies sich als zu lang und die Leute begannen, es einfach das Buch der Viererbande zu nennen. Die erste Auflage umfasste 23 Muster. Danach wurden Dutzende anderer Muster entdeckt.
Ein Entwurfsmuster ist eine standardisierte Lösung für ein häufiges Problem.
Und das Singleton- Muster ist nur eines davon.

Warum brauchen wir Designmuster?

Sie können programmieren, ohne Muster zu kennen: Schließlich haben Sie mit Level 15 bereits Hunderte von Miniprogrammen auf CodeGym geschrieben, ohne überhaupt zu wissen, dass sie existieren. Dies deutet darauf hin, dass es sich bei Entwurfsmustern um eine Art Werkzeug handelt, dessen Verwendung den Meister vom Laien unterscheidet: Entwurfsmuster beschreiben, wie ein typisches Problem richtig gelöst werden kann. Das bedeutet, dass Sie Zeit sparen, wenn Sie Muster kennen. In dieser Hinsicht ähneln sie Algorithmen. Sie könnten beispielsweise Ihren eigenen Sortieralgorithmus mit Blackjack und Zahlen erstellenund viel Zeit damit verbringen, oder Sie könnten etwas umsetzen, das schon lange verstanden und beschrieben wurde. Das Gleiche gilt für Designmuster. Darüber hinaus wird der Code mit Entwurfsmustern standardisierter, und wenn Sie das entsprechende Muster verwenden, ist es weniger wahrscheinlich, dass Sie Fehler machen, da die häufigsten Fallstricke des Musters schon vor langer Zeit erkannt und beseitigt wurden. Darüber hinaus hilft die Kenntnis von Mustern den Programmierern, sich gegenseitig besser zu verstehen. Sie können einfach den Namen eines Musters sagen, anstatt zu versuchen, Ihren Programmierkollegen eine ausführliche Erklärung zu geben. Zusammenfassend lässt sich sagen, dass Designmuster Ihnen dabei helfen:
  • das Rad nicht neu erfinden, sondern Standardlösungen nutzen;
  • Code standardisieren;
  • Terminologie standardisieren;
Zum Abschluss dieses Abschnitts stellen wir fest, dass die gesamten Entwurfsmuster in drei große Gruppen unterteilt werden können: Muster und Singleton – für alle, die ihnen zum ersten Mal begegnen – 2

Zum Schluss das Singleton-Muster

Singleton ist ein Schöpfungsmuster . Dieses Muster stellt sicher, dass es nur eine Instanz einer Klasse gibt und stellt einen globalen Zugriffspunkt für dieses Objekt bereit. Aus der Beschreibung sollte klar hervorgehen, dass dieses Muster in zwei Fällen angewendet werden sollte:
  1. wenn Ihr Programm erfordert, dass nicht mehr als ein Objekt einer bestimmten Klasse erstellt werden darf. Beispielsweise könnte ein Computerspiel eine Hero-Klasse und nur ein Hero-Objekt haben, das den einzigen Helden im Spiel beschreibt.

  2. wenn Sie einen Punkt für den globalen Zugriff auf ein Objekt bereitstellen müssen. Mit anderen Worten: Sie müssen das Objekt von überall im Programm verfügbar machen. Leider reicht es nicht aus, einfach eine globale Variable zu erstellen, da diese nicht schreibgeschützt ist: Jeder kann den Wert der Variablen ändern, sodass der globale Zugriffspunkt des Objekts möglicherweise verloren geht. Diese Eigenschaften eines Singletons sind beispielsweise erforderlich, wenn Sie ein Objekt haben, das mit einer Datenbank arbeitet, und Sie von verschiedenen Teilen des Programms aus auf die Datenbank zugreifen müssen. Ein Singleton stellt sicher, dass niemand Code schreibt, der die zuvor erstellte Instanz ersetzt.
Ein Singleton erfüllt also diese beiden Anforderungen: Es darf nur ein Objekt einer bestimmten Art im Programm vorhanden sein und es muss globaler Zugriff darauf möglich sein. Im Beispiel auf Level 15 bittet Sie der Kapitän, dieses Muster für die folgende Aufgabe umzusetzen:
  1. Finden Sie ein Beispiel für Singleton mit verzögerter Initialisierung.

  2. Erstellen Sie nach demselben Prinzip drei Singleton-Klassen – Sonne, Mond, Erde – in separaten Dateien.

  3. ImplementierenPlanetSchnittstelle in den Klassen Sonne , Mond und Erde .

  4. Rufen Sie im statischen Block der Solution- Klasse die aufreadKeyFromConsoleAndInitPlanetMethode.

  5. Implementieren Sie diereadKeyFromConsoleAndInitPlanetMethodenfunktionalität:

    • 5.1. Liest einen String- Parameter aus der Konsole

    • 5.2. Wenn der Parameter gleich einem der istPlanetErstellen Sie für die Konstanten der Schnittstelle ein geeignetes thePlanet- Objekt.

Nachdem wir die Aufgabenbedingungen sorgfältig gelesen haben, können wir klar erkennen, warum hier ein Singleton benötigt wird. Tatsächlich werden wir gebeten, eine Instanz jeder der folgenden Klassen zu erstellen: Sonne , Mond , Erde . Es ist sinnvoll anzunehmen, dass wir nicht mehr als eine Sonne/einen Mond/eine Erde erschaffen sollten. Andernfalls geraten wir in eine absurde Situation, es sei denn, Sie schreiben Ihre Version von Star Wars. Implementierung des Singleton- Musters in Java in drei Schritten In Java kann das Singleton-Verhalten nicht mit einem gewöhnlichen Konstruktor implementiert werden, da ein Konstruktor immer ein neues Objekt zurückgibt. Daher alle Implementierungen von SingletonEs geht darum, den Konstruktor zu verbergen, eine öffentliche statische Methode zu erstellen, die die Lebensdauer des Singleton-Objekts steuert, und alle neu erscheinenden Objekte zu „zerstören“. Wenn auf einen Singleton zugegriffen wird, sollte dieser entweder ein neues Objekt erstellen (sofern noch keins im Programm vorhanden ist) oder ein vorhandenes zurückgeben. Um das zu erreichen:
  1. Sie müssen der Klasse ein privates statisches Feld zuweisen, das ein einzelnes Objekt speichert:

    
    public class LazyInitializedSingleton {
    	private static LazyInitializedSingleton instance; // #1
    }
    
  2. Machen Sie den (Standard-)Konstruktor privat. Dies bedeutet, dass außerhalb der Klasse nicht darauf zugegriffen werden kann und keine neuen Objekte zurückgegeben werden können:

    
    public class LazyInitializedSingleton {
    	private static LazyInitializedSingleton instance;
    private LazyInitializedSingleton(){} // #2
    } 
    
  3. Deklarieren Sie eine statische Erstellungsmethode, die zum Abrufen des Singletons verwendet wird:

    
    public class LazyInitializedSingleton {
        private static LazyInitializedSingleton instance;
            private LazyInitializedSingleton() {}
            public static LazyInitializedSingleton getInstance() { // #3
            if (instance == null) { // If the object has not yet been created
                instance = new LazyInitializedSingleton(); // Create a new object
            }
            return instance; // Return the previously created object
        }
    }
    
Das obige Beispiel ist etwas umständlich, da wir den Konstruktor einfach verstecken und unsere eigene Methode anstelle eines Standardkonstruktors bereitstellen. Da dieser Artikel sicherstellen soll, dass CodeGym-Studenten mit diesem Muster (und Designmustern im Allgemeinen) in Kontakt kommen, werden die Nuancen komplexerer Singleton-Implementierungen hier nicht beschrieben. Wir weisen lediglich darauf hin, dass dieses Muster je nach Komplexität des Programms möglicherweise weiter verfeinert werden muss. Beispielsweise können in einer Multithread-Umgebung (siehe Artikel über Threads) mehrere verschiedene Threads gleichzeitig auf die Singleton-Methode zugreifen und der oben beschriebene Code nicht mehr funktionieren, da jeder einzelne Thread eine Instanz der Klasse erstellen könnte. Daher gibt es immer noch verschiedene Ansätze zum Erstellen geeigneter threadsicherer Singletons. Aber das ist eine andere Geschichte =)

Und schließlich ... Was ist diese verzögerte Initialisierung, nach der der Kapitän gefragt hat?

Die verzögerte Initialisierung wird auch als verzögerte Initialisierung bezeichnet. Dies ist ein Programmiertrick, bei dem ein ressourcenintensiver Vorgang (und das Erstellen eines Objekts ist ein ressourcenintensiver Vorgang) bei Bedarf und nicht im Voraus ausgeführt wird. Was passiert also eigentlich in unserem Singleton- Java-Code? Mit anderen Worten: Unser Objekt wird zum Zeitpunkt des Zugriffs erstellt, nicht im Voraus. Sie sollten nicht davon ausgehen, dass die verzögerte Initialisierung irgendwie starr an das Singleton- Muster gebunden ist . Die verzögerte Initialisierung wird auch in anderen kreativen Entwurfsmustern wie der Proxy- und der Factory-Methode verwendet, aber das ist auch eine andere Geschichte =)
Kommentare
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION