Lekce 2 - Singleton (jedináček)
V minulé lekci, Factory (tovární metoda), jsme si ukázali návrhový vzor Factory, který odděluje vytváření instance od samotného programu.
Singleton je další populární návrhový vzor, který umožňuje zajistit globální přístup k instanci nějaké třídy.
Motivace
Někdy v programu potřebujeme sdílet jednu instanci mezi několika bloky, objekty atd., aniž bychom ji museli stále předávat v konstruktoru. Ukázkový příklad je databázové připojení, celý program pracuje s jedním připojením a bylo by nepraktické ho stále předávat. Nabízí se řešení udělat třídu poskytující databázové API jako statickou. Může však nastat případ, kdy se nám hodí ji mít instanciovatelnou (např. někdy pracujeme s více připojeními) nebo používáme hotovu třídu, která statická není. Vložíme ji tedy do Singletonu.
Vzor
Vzor je tvořen třídou, která se stará o to, aby její instance existovala jen jednou.
Jako první musíme uživateli zakázat tvořit instanci, toho docílíme implementací prázdného privátního konstruktoru.
Dále vytvoříme běžnou instanční proměnnou a do ní vložíme instanci, kterou chceme v programu sdílet. V našem případě tedy instanci databázového připojení.
Nyní si třída vytvoří instanci sebe sama a tu uloží do statické proměnné. Instanci má takto ve správě třída a uživatel se k ní jinak než přes ni nedostane, protože ji nemůže vytvořit. Máme ji tedy zcela pod kontrolou. Instanci nastavíme samozřejmě jako privátní a také pouze pro čtení.
Nakonec vytvoříme veřejnou metodu, přes kterou budeme zvenku k instanci přistupovat. Uvnitř instanci vrátíme.
Ukázkový zdrojový kód
-
class Singleton { private Singleton() { } public Databaze databaze = new Databaze('host', 'jmeno', 'heslo'); private static readonly Singleton instance = new Singleton(); public static Singleton vratInstanci() { return instance; }
-
<?php class Singleton { // datový typ vlastnosti až od PHP verze 7.4 private static Singleton $instance; public static Databaze $db; private function __construct() { // PHP nepodporuje výrazy ve vlastnostech třídy, je třeba instanciovat v konstruktoru: self::$db = new Databaze('host', 'jmeno', 'heslo'); } // datový typ metody až od PHP verze 7 public static function vratInstanci() : Singleton { return new Singleton(); } }
Použití v programu
K připojení poté v programu přistupujeme takto:
-
Pripojeni pripojeni = Singleton.vratInstanci();
-
$pripojeni = Singleton::vratInstanci();
Singleton znamená jedináček, tedy instance, která nemá žádné sourozence.
Možné modifikace
Metoda k navrácení instance přímo vybízí k tomu, abychom inicializaci instance provedli až ve chvíli, kdy ji potřebujeme. Kód tedy můžeme modifikovat takto:
-
class Singleton { private Singleton() { } public Databaze databaze = new Databaze('host', 'jmeno', 'heslo'); private static Singleton instance = null; public static Singleton vratInstanci() { if (instance == null) instance = new Singleton(); return instance; } }
-
<?php class Singleton { // datový typ vlastnosti až od PHP verze 7.4 private static Singleton $instance; public static Databaze $db; private function __construct() { // PHP nepodporuje výrazy ve vlastnostech třídy, je třeba instanciovat v konstruktoru: self::$db = new Databaze('host', 'jmeno', 'heslo'); } // datový typ metody až od PHP verze 7 public static function vratInstanci() : Singleton { if (self::$instance === null) { self::$instance = new self; } return self::$instance; } }
Někdy takto můžeme optimalizovat výkon programu. Verze není thread safe a v případě, že bychom pracovali s více vlákny, je třeba dát inicializaci instance do locku.
Nevýhody
Slovo globální může být poněkud kontroverzní a Singleton je kvůli tomu někdy označován jako anti-pattern, tedy špatný vzor. Ačkoli Singleton by měl každý programátor znát, určitě to není ideální vzor pro předávání závislostí v aplikaci. Pro své problémy je dokonce součástí antipraktik STUPID. Lepším vyřešením závislostí je vzor Dependency Injection. Pokud vás tato problematika zajímá, doporučuji náš kurz Softwarové architektury a depencency injection. Thread-safe napsaný Singleton může být výhodné použít ve vícevláknových aplikacích.
V další lekci, Prototype, si ukážeme návrhový vzor Prototype, který vytváří nové instance na základě existujících, tzv. prototypů, které naklonuje. Umožňuje nám tak nahradit konstrukci switch.
Komentáře


Zobrazeno 10 zpráv z 21. Zobrazit vše