Singleton (Singelton)

Introduktion

Singleton är ett skapande mönster som säkerställer att en klass endast har en instans och tillhandahåller en global åtkomstpunkt till den.


Problem

Singleton-mönstret löser två problem samtidigt (vilket tekniskt sett bryter mot Single Responsibility Principle):

  1. En enda instans — Viss kod kräver exakt en instans av en klass, t.ex. en databasanslutning eller ett konfigurationsobjekt. Skapar du flera instanser riskerar du race conditions, inkonsekvent data och onödig resursåtgång.
  2. Global åtkomst — Objektet ska vara åtkomligt från var som helst i programmet, men skyddad från att skrivas över av misstag.

Lösning

Alla Singleton-implementationer delar dessa två egenskaper:

  • Privat konstruktor — Förhindrar att andra klasser skapar instanser med new.
  • Statisk åtkomstmetod — En metod som skapar instansen vid första anropet och returnerar den cachade instansen vid alla efterföljande anrop.

När ska Singleton användas?

  • När en klass i ditt program bara ska ha en enda instans för alla klienter.
  • T.ex. delad databasanslutning, logg-system, konfigurationshanterare, connection pool.

Struktur

DelBeskrivning
Privat konstruktorHindrar direkt instansiering.
Statiskt privat fältLagrar den enda instansen.
Statisk getInstance()Skapar (lazy) eller returnerar den befintliga instansen.

Exempel — Databasanslutning (Java)

Scenariot: En databasklass som garanterar att bara en anslutning skapas, även i flertrådade miljöer.

public final class Database {
    // Det statiska fältet för den enda instansen
    private static volatile Database instance;
    private String connectionString;

    // Privat konstruktor — ingen kan anropa new Database()
    private Database(String connectionString) {
        // Simulera en tidskrävande initiering
        try { 
	        Thread.sleep(500); 
        } catch (InterruptedException e) { 
	        Thread.currentThread().interrupt(); }
	        this.connectionString = connectionString;
	        System.out.println("Databas initierad: " + connectionString);
	    }

    // Thread-safe lazy initialization med double-checked locking
    public static Database getInstance(String connectionString) {
        if (instance == null) {
            synchronized (Database.class) {
                if (instance == null) {
                    instance = new Database(connectionString);
                }
            }
        }
        return instance;
    }

    public void query(String sql) {
        System.out.println("[" + connectionString + "] Kör: " + sql);
    }
}

// ── Klientkod ─────────────────────────────────────────────

public class Application {
    public static void main(String[] args) {
        Database db1 = Database.getInstance("jdbc:mysql://localhost/bytebase");
        Database db2 = Database.getInstance("jdbc:mysql://localhost/bytebase");

        System.out.println("Samma instans? " + (db1 == db2)); // true

        db1.query("SELECT * FROM patterns");
        db2.query("INSERT INTO patterns VALUES (...)");
        // Båda anropen går mot SAMMA anslutning
    }
}

Output:

Databas initierad: jdbc:mysql://localhost/bytebase
Samma instans? true
[jdbc:mysql://localhost/bytebase] Kör: SELECT * FROM patterns
[jdbc:mysql://localhost/bytebase] Kör: INSERT INTO patterns VALUES (...)

Singleton i Spring Boot

I modern Spring Boot-utveckling behöver du sällan implementera Singleton manuellt. Spring hanterar detta via sin IoC-container — alla @Component- och @Service-klasser är som standard Singletons:

@Service
public class DatabaseService {
    // Spring garanterar att bara EN instans skapas i applikationskontexten
    public void query(String sql) { /* ... */ }
}

Fördelar

  • Garanterar att en klass bara har en instans.
  • Global åtkomstpunkt till instansen.
  • Instansen initieras bara när den faktiskt behövs (lazy initialization).

Nackdelar

  • Kan dölja dålig design — komponenter som “vet för mycket” om varandra.
  • Kräver extra hantering i flertrådade miljöer.
  • Svårt att enhetstest — Singletons bär tillstånd mellan tester.

Av Victor Hernandez från Bytebase.se