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:

  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 inkonsekvent data och onödig resursåtgång.
  2. Global åtkomst — Objektet ska vara åtkomligt från var som helst i programmet, men skyddat från att skrivas över av misstag.

Lösning

  • Privat konstruktor — Förhindrar att andra klasser skapar instanser med new.
  • Statisk åtkomstmetod — 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.

Struktur

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

Exempel — Databasanslutning (TypeScript)

Scenariot: En databasklass som garanterar att bara en anslutning skapas i hela applikationen.

class Database {
  private static instance: Database | null = null;
  private connectionString: string;

  // Privat konstruktor — ingen kan anropa new Database()
  private constructor(connectionString: string) {
    this.connectionString = connectionString;
    console.log(`Databas initierad: ${connectionString}`);
  }

  // Statisk åtkomstmetod
  static getInstance(connectionString: string): Database {
    if (!Database.instance) {
      Database.instance = new Database(connectionString);
    }
    return Database.instance;
  }

  query(sql: string): void {
    console.log(`[${this.connectionString}] Kör: ${sql}`);
  }
}

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

const db1 = Database.getInstance('postgresql://localhost/bytebase');
const db2 = Database.getInstance('postgresql://localhost/bytebase');

console.log('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: postgresql://localhost/bytebase
Samma instans? true
[postgresql://localhost/bytebase] Kör: SELECT * FROM patterns
[postgresql://localhost/bytebase] Kör: INSERT INTO patterns VALUES (...)

Singleton i Node.js

I Node.js-moduler uppnår du ofta Singleton-beteende gratis via modulsystemet — en modul cachas efter första require/import:

// database.ts — exporteras som en singleton automatiskt av Node.js modul-cache
class Database {
  private connectionString = 'postgresql://localhost/bytebase';
  query(sql: string) { console.log(`Kör: ${sql}`); }
}

export const db = new Database(); // En instans, delad överallt

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.
  • Svårt att enhetstest — Singletons bär tillstånd mellan tester.
  • I TypeScript/JavaScript behöver du sällan mönstret explicit tack vare modulsystemet.

Av Victor Hernandez från Bytebase.se