Body zdarma Java týden
Využij podzimních slev a získej od nás až 40 % bodů zdarma! Více zde
Pouze tento týden sleva až 80 % na Java e-learning!

Singleton (jedináček)

Unicorn College Tento obsah je dostupný zdarma v rámci projektu IT lidem.
Vydávání, hosting a aktualizace umožňují jeho sponzoři.

Singleton je 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.

Tento výukový obsah pomáhají rozvíjet následující firmy, které dost možná hledají právě tebe!

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 (C#)

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;
    }
}

Použití v programu

K připojení poté v programu přistupujeme takto:

Pripojeni 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;
    }
}

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. 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.


 

 

Článek pro vás napsal David Čápka
Avatar
Jak se ti líbí článek?
13 hlasů
Autor pracuje jako softwarový architekt a pedagog na projektu ITnetwork.cz (a jeho zahraničních verzích). Velmi si váží svobody podnikání v naší zemi a věří, že když se člověk neštítí práce, tak dokáže úplně cokoli.
Unicorn College Autor sítě se informační technologie naučil na Unicorn College - prestižní soukromé vysoké škole IT a ekonomie.
Všechny články v sekci
GOF - Vzory pro vytváření
Aktivity (5)

 

 

Komentáře
Zobrazit starší komentáře (10)

Avatar
dlouhyjoosef
Člen
Avatar
dlouhyjoosef:22.1.2015 13:53

Dobry den. Nevim zda jsem to umistil spravne kdyztak prosim presunout. Mam na pad na zajimavy program ale neumim programovat mozna by to nekoho tady zaujalo a zkusil ho udelat. Resi se to pres maily nebo primo tady na foru ? Diky

 
Odpovědět  -6 22.1.2015 13:53
Avatar
zpavlu
Redaktor
Avatar
zpavlu:10.9.2016 20:29

Při procházení knihy „Modern C++ Design: Generic Programming and Design Patterns Applied“ od autora Andrei Alexandrescu jsem narazil na zajímavý problém pro otázku implementace Singletonu.
Knihu si můžeme stáhnout zde
O co se jedná:
• Máme tři Singletony pro řízení Klávesnice, Obrazovky a Deníku implementované jako Meyersovy Singletony.
• První dva modelují své protějšky a třetí slouží pro zápis chyb (na příklad textový soubor).
• Deník pro svou činnost potřebuje nějaké prostředky a proto bude vytvořen pouze objeví-li se nějaká chyba. Pokud není chyba, nebude Deník vytvořen.
• Program Deník oznamuje jakoukoliv chybu jak Klávesnice nebo Obrazovky .
• Předpokládejme, že po úspěšné implementaci Klávesnice se nepodaří inicializovat třídu Obrazovka. Pak konstruktor třídy Klávesnice inicializuje a vytvoří Deník, chyba je zaznamenána a program Deník je ukončen spolu s aplikací. Při ukončení jsou odstraněny lokální statické objekty v obráceném pořadí jejich vzniku. Deník je odstraněn před instancí Klávesnice. Pokud se z nějakého důvodu Klávesnice neodstraní, pak zkusí oznámit chybu programu Deník.
• Deník::Instance nevědomky vrací odkaz na slupku odstraněného objektu Deník. Náš program se začíná chovat nedefinovaně. Vzniká problém mrtvého odkazu.
• Pořadí odstraňování objektů Klávesnice, Deník a Obrazovka není definován. Je potřeba, aby Klávesnice a Obrazovka, poslední vytvořený je odstraněn jako první (pravidlo C++) a zároveň musíme z tohoto pravidla vyjmout Deník. Nezávisle na tom, kdy byl vytvořen musí být odstraněn poslední, aby mohl zachytit chyby předchozích obou.
Používáme-li v aplikaci více interagujících Singletonů, nelze používat automatickou kontrolu doby jejich existence. Dobře navržený Singleton by měl mrtvý odkaz detekovat.

Chtěl bych ukázat jak autor řešil tento návrhový vzor a jak postupně dospěl a implementoval generickou šablonu třídy SingletonHolder. Existují různé implementace Singletonů, jejich vhodnost závisí na problému, který řešíme. Veškeré ukázky jsou použité z této knihy bez úprav, autor je dal volně k dispozici. Totéž platí pro soubor „LokiLibrary.lib“ z knihovny „Loki“.

Pár slov k Mariovy, myslíš si,že když napíšeš kousek kódu bez jediné poznámky, že všichni pochopí smysl?

První díl najdete na mém webu.

Odpovědět 10.9.2016 20:29
PZ
Avatar
havlat82
Člen
Avatar
havlat82:4.5.2018 11:25

ahoj, objevil sem zajímavej odkaz na téma návrhový vzory. třeba někomu příde užitečnej.. DoFactory

 
Odpovědět 4.5.2018 11:25
Avatar
virlupus.soft
Redaktor
Avatar
virlupus.soft:15. dubna 3:05

Krásné poučné, ale přece jen.... vzor či protivzor. Statika. Globální věci? Není to trochu nebezpečné a netestovatelné. K čemu se vlastně jedináček dá použít? Jo třeba jako kontejner pro předání závislostí. Fakt nevím, použil jsem jej jen jednou. Dělal jsi emulátor ZX Spectra a kromě vlákna navíc pro procesor jsem potřeboval pamět a od adresy 0x4000 udělat obraz. Tedy screen, memory, cpu, io.... tam se mi singleton hodil.... ale pak.... jiná paměť a jiná struktura uvnitř.
A do háje s návrhem... celé jinak.
Abstrakce, Interface. naštěstí nebylo nutno něco jako DC (Depency Contejner)....
Ale to bylo dávno. Prostě Singleton bych doporučit nemohl

 
Odpovědět 15. dubna 3:05
Avatar
Patrik Pastor:21. června 17:49

proc je instance static kdyz je private. Statika je prece abych venku mimo vlastni tridu pristupoval k metodam/vlastnostem statick prea tridu bez instance. Proc je tedy private static? (dava mi to smysl jenom u public static, kde prave venku pristupuju, jak sem to nahore popsal). Ale private, prece ve vlastni tride nebudu priatupovat k metodam/vlastnostem pres vlastni tridu, kdyz v te vlastni tride jsem.

 
Odpovědět 21. června 17:49
Tento výukový obsah pomáhají rozvíjet následující firmy, které dost možná hledají právě tebe!
Avatar
Odpovídá na Patrik Pastor
Michal Šmahel:22. června 11:38

Ahoj, nevím, kde studuješ, ale chtělo by to se danými tématy zaobírat více do hloubky.

K tvému dotazu. Jelikož nevíš, jak statika funguje, nemůžeš tomu logicky moc porozumět. Statika narozdíl od běžného (dynamického, instančního) přístupu nepotřebuje ke své funkčnosti instanci, patří třídě a také se na ní volá. Z tohoto důvodu můžeš veřejné statické metody volat přímo na třídě, nemusíš tvořit objekt. To je ostatně výhoda, kterou jsi popsal. Podobný důsledek to má pro zapouzdřené metody (soukromé a protected). Ty také nepracují na instanci, takže mohou ukládat data (a pracovat s nimi), která by po zrušení instance "zmizela". V praxi se to často používá pro uchování stavových dat. Tyto privátní statické metody jsou často volané těmi veřejnými.

Ve tvém příkladu je instance privátní, aby ji nebylo možné měnit zvenčí a statická, aby s ní mohly pracovat statické metody a instalace byla uchována po celou dobu běhu aplikace. K její změně slouží veřejná statická metoda. Je to jeden z principů Singletonu (Jedináčka), který zabraňuje jakkoliv vytvořit další instanci nějaké třídy, umožní vždy pouze jednu.

Odpovědět  +1 22. června 11:38
Nejdůležitější je motivace, ovšem musí být doprovázena činy.
Avatar
Odpovídá na Michal Šmahel
Patrik Pastor:22. června 13:45

no tady je staticka metoda vratInstanci() kde je navratovy typ prave private static instance, tudiz v tomto konkretnim pripadu to chapu, protoze nemuze klasicka metoda vracet staticky typ, takze toto je ok. Ale v jakem jinem pripade (kdybych nevracel statiku) pro me mela smysl davat prive static? pokud by se v nejake verejne metode pracovalo se statikou (data uklada a s nimi pracovat) ale navratovu typ by nebyl (byl by void), potom tato metoda by nepotrebovala byt staticka (ackoliv se statikckou metodou/property pracuje), takze private static ... (neco) asi neni az tak moc pouzivane coz?

 
Odpovědět 22. června 13:45
Avatar
Odpovídá na Patrik Pastor
Michal Šmahel:22. června 16:18

Statika by se obecně moc používat neměla. V případě špatné implementace je to úplné zlo. V praxi jde navíc téměř vždy nahradit něčím jiným. Singleton patří mezi několik dobrých využití statiky, i když využití Singletonu také není moc velké.

Statika se dá používat ještě třeba na čítač instancí. Do konstruktoru vložíš inkrementaci privátní statické vlastnosti. Potom, pokud potřebuješ někde s počtem instancí operovat, využiješ data právě z této vlastnosti.

Editováno 22. června 16:19
Odpovědět 22. června 16:18
Nejdůležitější je motivace, ovšem musí být doprovázena činy.
Avatar
h.grulich
Člen
Avatar
Odpovídá na Michal Šmahel
h.grulich:9. října 10:45

Nemyslím si, takové čítače by spíš měly být ve faktorce těchto instancí.
Když potřebuješ s počtem instancí operovat, potřebuješ to i testovat a jsi opět u problému s testovatelností.

 
Odpovědět 9. října 10:45
Avatar
Odpovídá na h.grulich
Michal Šmahel:9. října 15:43

Ahoj, souhlasím s tvým tvrzením. Svou zprávu jsem bohužel pojal spíše pro začátečníka.

Osobně se statice zcela vyhýbám, pokud je nějaké východisko. Již v návrhu počítám s entitami, které v případě potřeby tvoří továrny. Určitě to považuji za mnohem lepší způsob. Jak jsi psal, testovat statiku je pěkný porod a člověk se tomu chce jistě vyhnout. Navíc jsou tu i další problémy.

Každopádně moc děkuji za doplnění. Jsem rád, že tu jsou lidé, kteří umí napsat rozumnou kritiku, která k něčemu je.

Odpovědět  +1 9. října 15:43
Nejdůležitější je motivace, ovšem musí být doprovázena činy.
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

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