Zweck: Stellt sicher, dass eine Klasse nur genau eine Instanz besitzt, und bietet einen globalen Zugriffspunkt darauf.
Problem: Manche Objekte (z. B. Konfiguration, Logger, Verbindungspool) dürfen aus Konsistenz- oder Ressourcengründen nur einmal existieren.
Lösung: Der Konstruktor wird privat gemacht, die Klasse verwaltet ihre eigene Instanz selbst und gibt sie über eine statische Methode (getInstance()) zurück.
privatenew Configuration() aufrufen – nur die Klasse selbst darf ihre eigene Instanz erzeugennew wird also weiterhin benutzt, aber nur intern innerhalb von getInstance(), nicht mehr direkt vom Nutzer der Klasse.private static Variable (instance) hält die einzige existierende Instanzstatic bedeutet, dass es diese Variable nur ein einziges Mal für die gesamte Klasse gibt, nicht pro ObjektgetInstance() prüft bei jedem Aufruf, ob instance noch null ist:
new Configuration() genau einmal ausgeführt und das Ergebnis in instance gespeichertinstance bereits gesetzt, der if-Block wird übersprungen und es findet kein weiteres new mehr statt – stattdessen wird einfach die vorhandene Referenz zurückgegeben.Beispiel:
public class Configuration {
private static Configuration instance;
private Configuration() { }
public static Configuration getInstance() {
if (instance == null) {
instance = new Configuration();
}
return instance;
}
}
Verwendung in einer main-Methode:
public class Main {
public static void main(String[] args) {
Configuration config1 = Configuration.getInstance();
Configuration config2 = Configuration.getInstance();
System.out.println(config1 == config2); // true – dieselbe Instanz
}
}
Vor-/Nachteile: Kontrollierter Zugriff, aber erschwert Testbarkeit (globaler Zustand) und kann bei Multithreading zu Problemen führen, wenn nicht synchronisiert.
maxVerbindungen) aus einer Konfiguration.public class Configuration {
private int maxVerbindungen = 10;
public Configuration() {
System.out.println("Neue Configuration wurde erstellt.");
}
public int getMaxVerbindungen() {
return maxVerbindungen;
}
public void setMaxVerbindungen(int wert) {
maxVerbindungen = wert;
}
}
############
public class Netzwerkdienst {
Configuration config = new Configuration();
public void starten() {
config.setMaxVerbindungen(50);
System.out.println("Netzwerkdienst startet mit maxVerbindungen=" + config.getMaxVerbindungen());
}
}
public class Datenbankdienst {
Configuration config = new Configuration();
public void starten() {
System.out.println("Datenbankdienst startet mit maxVerbindungen=" + config.getMaxVerbindungen());
}
}
############
public class Main {
public static void main(String[] args) {
Netzwerkdienst netzwerkdienst = new Netzwerkdienst();
Datenbankdienst datenbankdienst = new Datenbankdienst();
netzwerkdienst.starten();
datenbankdienst.starten();
}
}
Problem:
Netzwerkdienst erzeugt seine eigene Configuration und setzt maxVerbindungen auf 50Datenbankdienst erzeugt eine eigene, unabhängige Configuration-Instanz und sieht deshalb weiterhin den Ausgangswert 10 – obwohl es sich eigentlich um dieselbe, anwendungsweite Einstellung handeln sollte.Die Ausgabe:
Netzwerkdienst startet mit maxVerbindungen=50
Datenbankdienst startet mit maxVerbindungen=10
Es gibt keinen gemeinsamen, konsistenten Konfigurationszustand.
public class Configuration {
private static Configuration instance; // die private statische Instanzvariable vom selben Typ wie die Klasse selbst ist Teil der Magic
private int maxVerbindungen = 10;
private Configuration() {
System.out.println("Neue Configuration wurde erstellt.");
}
public static Configuration getInstance() { // hier geht die Magic weiter
if (instance == null) { // wenn es noch keine Instanz gibt ...
instance = new Configuration(); // dann erzeuge eine
}
return instance; // ansonsten: gib die bestehende zurück
}
public int getMaxVerbindungen() {
return maxVerbindungen;
}
public void setMaxVerbindungen(int wert) {
maxVerbindungen = wert;
}
}
############
public class Netzwerkdienst {
Configuration config = Configuration.getInstance(); // und hier jetzt die Erzeugung eines Objekts nach den Regeln der Configuration (s.o)
public void starten() {
config.setMaxVerbindungen(50);
System.out.println("Netzwerkdienst startet mit maxVerbindungen=" + config.getMaxVerbindungen());
}
}
public class Datenbankdienst {
Configuration config = Configuration.getInstance(); // und hier jetzt die Erzeugung eines Objekts nach den Regeln der Configuration (s.o)
public void starten() {
System.out.println("Datenbankdienst startet mit maxVerbindungen=" + config.getMaxVerbindungen());
}
}
############
public class Main {
public static void main(String[] args) {
Netzwerkdienst netzwerkdienst = new Netzwerkdienst();
Datenbankdienst datenbankdienst = new Datenbankdienst();
netzwerkdienst.starten();
datenbankdienst.starten();
}
}
Lösung:
Configuration ist jetzt private, sodass niemand außerhalb der Klasse new Configuration() aufrufen kanngetInstance() erzeugt die Instanz beim ersten Aufruf (lazy initialization) und gibt bei jedem weiteren Aufruf dieselbe Instanz zurückNetzwerkdienst und Datenbankdienst kennen sich gegenseitig nicht, greifen aber beide über Configuration.getInstance() auf dieselbe Instanz zu.Ausgabe:
Netzwerkdienst startet mit maxVerbindungen=50
Datenbankdienst startet mit maxVerbindungen=50
Datenbankdienst sieht jetzt korrekt den von Netzwerkdienst geänderten Wert, weil beide dieselbe Configuration-Instanz verwenden.