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:
- En enda instans — Viss kod kräver exakt en instans av en klass, t.ex. en databasanslutning. Skapar du flera instanser riskerar du inkonsekvent data och onödig resursåtgång.
- 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
| Del | Beskrivning |
|---|---|
| Privat konstruktor | Hindrar direkt instansiering. |
| Statiskt privat fält | Lagrar den enda instansen. |
Statisk getInstance() | Skapar (lazy) eller returnerar den befintliga instansen. |
Exempel — Databasanslutning (PHP)
Scenariot: En databasklass som garanterar att bara en anslutning skapas i hela applikationen.
<?php
final class Database
{
private static ?Database $instance = null;
private string $connectionString;
// Privat konstruktor — ingen kan anropa new Database()
private function __construct(string $connectionString)
{
$this->connectionString = $connectionString;
echo "Databas initierad: {$connectionString}\n";
}
// Förhindra kloning
private function __clone() {}
// Statisk åtkomstmetod
public static function getInstance(string $connectionString): static
{
if (static::$instance === null) {
static::$instance = new static($connectionString);
}
return static::$instance;
}
public function query(string $sql): void
{
echo "[{$this->connectionString}] Kör: {$sql}\n";
}
}
// ── Klientkod ─────────────────────────────────────────────
$db1 = Database::getInstance('mysql:host=localhost;dbname=bytebase');
$db2 = Database::getInstance('mysql:host=localhost;dbname=bytebase');
echo 'Samma instans? ' . ($db1 === $db2 ? 'ja' : 'nej') . "\n"; // ja
$db1->query('SELECT * FROM patterns');
$db2->query('INSERT INTO patterns VALUES (...)');
// Båda anropen går mot SAMMA anslutning
Output:
Databas initierad: mysql:host=localhost;dbname=bytebase
Samma instans? ja
[mysql:host=localhost;dbname=bytebase] Kör: SELECT * FROM patterns
[mysql:host=localhost;dbname=bytebase] Kör: INSERT INTO patterns VALUES (...)
Singleton i Laravel
I Laravel hanteras Singleton-beteende via Service Container. Du registrerar en klass som singleton i en Service Provider:
// AppServiceProvider.php
public function register(): void
{
$this->app->singleton(Database::class, function () {
return new Database('mysql:host=localhost;dbname=bytebase');
});
}
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.
- Moderna ramverk som Laravel hanterar detta bättre via Dependency Injection.
Av Victor Hernandez från Bytebase.se