Singleton 1 1 1.

Slides:



Advertisements
Podobné prezentace
A1PRG - Programování – Seminář Ing. Michal Typová konverze, oblast platnosti, paměťové třídy 9 Verze
Advertisements

(instance konkrétní třídy)
Seminář C++ 5. cvičení Dědičnost Ing. Jan Mikulka.
Programovací jazyk C++
Přednáška 11 Jiří Šebesta
Úvod do objektově orientovaného programování
Pole, ukazatele a odkazy
ÚVOD DO CPP 7 Dědičnost - pokračování
BLIŽŠÍ POHLED NA TŘÍDY, DĚDIČNOST - úvod
PJV151 Vnořené a vnitřní členy mohou být členy tříd a interfejsů. Je-li X obalem Y a Y je obalem Z, pak Z získá jméno X$Y$Z - kompilací vzniknou classy.
Singleton 1 1.
C++ Přednáška 3 Konstantní a statické členy tříd, ukazatel this, konstantní instance třídy Ing. Jiří Kulhánek , kat. 352, VŠB TU Ostrava 2004.
Principy překladačů Běhová podpora Jakub Yaghob. Běhová podpora Statická podpora jazyka Překladač Interface na knihovny Hlavičkové soubory Dynamická podpora.
Algoritmizace a programování
Čtvrté cvičení Objektové programování Objektový model v Javě
C++0x stručný náhled na nadcházející revizi standardu programovacího jazyka C++ (ISO/IEC 14882) Jan Ringoš.
J a v a Začínáme programovat Lucie Žoltá metody, objekty, konstruktor.
Chain of responsibility Martin Malý prezentace na předmět Návrhové vzory (PRG024) na MFF UK
State. State – kontext a problém Kontext  chování objektu má záviset na jeho stavu, který se typicky mění za běhu Neflexibilní řešení  metody obsahují.
Páté cvičení Dědičnost Interface Abstarktní třídy a metody
Seminář C cvičení STL, Trolltech Ing. Jan Mikulka.
C# - Exceptions (výjimky)
Objektové programování
Jedenácté cvičení Vlákna. Java cv112 Vlákna Operační systém Mutitasking – více úloh se v operačním programu vykonává „současně“ Java Multithreading -
Seminář C cvičení Obsluha výjimek Ing. Jan Mikulka.
PRÁCE S VLÁKNY A APLIKAČNÍ DOMÉNY V.NET FRAMEWORK APLIKACÍCH Architektura technologie.NET Jan Martinovič, FEI - Katedra Informatiky.
Strategy. Strategy – „All-in-1“ na začátek class AStrategy { public: virtual void Algorithm()=0; protected: AStrategy(); }; class SpecificStrategy: public.
6. cvičení Polymorfismus
A1PRG - Programování – Seminář Ing. Michal Ukazatele a pole 10 Verze
Počítače a programování 1
PB161 Právo friend, přetěžování operátorů, přetypování PB161 | Friend, operátory PB161 – Programování v jazyce C++ Objektově Orientované Programování.
Memento. Obnovení operačního systému ( Windows | Linux...) Všichni víme, co jsou transekce v databázi Memento – zálohování databáze.
KIV/PPA1 cvičení 8 Cvičící: Pavel Bžoch. Osnova cvičení Objekty v Javě Třída Konstruktor Metody Metody a proměnné třídy x instance Program sestávající.
OSNOVA: a) Úvod do OOPb) Třídy bez metod c) Třídy s metodamid) Konstruktory a destruktory e) Metody constf) Knihovní třídy g) Třídy ve tříděh) Přetížení.
PB161 Principy OOP - rozhraní, dědičnost PB161 | Principy OOP - Dědičnost, rozhraní
C# - předávání parametrů Centrum pro virtuální a moderní metody a formy vzdělávání na Obchodní akademii T.G. Masaryka, Kostelec nad Orlicí.
IB111 Programování a algoritmizace
Návrh a tvorba WWW Přednáška 5 Úvod do jazyka PHP.
Dědičnost - inheritance dědičnost je jednou z forem znovupoužitelnosti dědičnost je jednou z forem znovupoužitelnosti B A Třída A je předkem třídy B Třída.
13/04/20151 Datový typ třída – class (1) Datový typ definovaný uživatelem Poskytuje mechanismus pro modelování entit, s nimiž manipulují aplikace Charakterizuje.
Principy OOP Objektově orientované programování vychá-zí ze třech základních principů (rysů): zapouzdření (encapsulation) dědičnost (inheritance) polymorfismus.
Počítače a programování 1 7.přednáška. Základy Pole ve třídách a metodách Pole Arrays.
FEL Komunikátor. Memory Leak program konsumuje operační paměť, kterou neumožňuje uvolnit o uvolnění paměti stará Garbage Collector ▫plně v režii Java.
Pokročilé programování v C++ (část B)
Ukazatele, řetězce Přednáška č. 3. Ukazatele  Ukazatel (pointer) – typ o velikosti 4 bajty (v 32bit. systémech) pro uložení adresy objektu na který ukazuje.
Jazyk C A0B36PRI - PROGRAMOVÁNÍ Část II.
Service layer. Service layer – úvod Problém  Vytvoření API aplikace  Odstínění bussiness logiky a transakčního chování od zbytku aplikace  Kam s aplikační.
Observer Martin Dráb Návrhové vzory, Co to je?  Definuje závislost 1:N mezi objekty  Závislé objekty jsou informovány o změně stavu  Konzistentní.
Pokročilé datové typy (struktury, unie, dynamické proměnné)
XSLT překladač Marek Běhálek Informatika a aplikovaná matematika FEI VŠB-TU Ostrava.
Strategy. Motivace Různé algoritmy pro stejnou akci Hromada kódu v mnoha podmínkách Důsledky  Komplexnost  Špatná čitelnost  Těžká správa kódu  Těžka.
Iterator Iterator – Problém struct Item { int _value; Item * _next; Item( int value, Item * next ) : _value( value ), _next( next ) { } }; void Print(
Funkce Přednáška č. 5. Funkce (functions)  posloupnost příkazů uvedená hlavičkou  využití – opakovaně volaná sekvence – strukturování programu – ošetření.
Template Method. Motivační příklad – reálný svět Čaj 1) Uvař vodu 2) Dej do hrnku sáček čaje 3) Zalij hrnek 4) Přisyp cukr a vymačkej citrón Káva 1) Uvař.
Iterator. C historie int * rand_numbers(int n) { int *numbers = malloc(n * sizeof(int)); int *it = numbers; while (it < numbers + n) *it++ = rand(); //
NÁZEV ŠKOLY: S0Š Net Office, spol. s r.o., Orlová-Lutyně AUTOR: Ing. Adéla Tomalová NÁZEV: Podpora výuky v technických oborech TEMA: Objektově orientované.
Programování v jazyce C++ Speciality jazyka C++, úvod do OOP.
Y36PJC Programování v jazyce C/C++
Úvod do C# - OOP Jaroslav BURDYS 4IT.
Programování ENUM, SWITCH,pole jednorozměrná a vícerozměrná, deklarace, inicializace, kopírování, porovnání Erik Král.
Y36PJC Programování v jazyce C/C++
Decorator Radek Zikmund NPRG024, LS 2016/17.
Singleton
Návrhový vzor Flyweight
Bridge.
C# přehled vlastností.
NÁZEV ŠKOLY: S0Š Net Office, spol. s r.o., Orlová-Lutyně
Unit of Work vzor z P of EAA (Fowler) 1.
Composite “Spojuj a panuj”.
Bridge.
Transkript prezentace:

Singleton 1 1 1

Co je singleton? Definice Proč jedna instance? Proč globální přístup?  Třída má právě 1 instanci  Existuje globální přístup k této instanci  Proč jedna instance?  Více instancí může být nežádoucí / zbytečné / nebezpečné  Proč globální přístup?  Použití z mnoha míst v programu  Vhodné použití  Logger  Databázové spojení 2 2 2

Co je singleton? Definice Traktorista ! Gobálny namespace  Třída má právě 1 instanci  Existuje globální přístup k této instanci  Traktorista ! Gobálny namespace Garden instance = new Garden(); void A() {     instance.doPlow(); } void B() {     instance.doPlant(); ! Více možných instancí TODO: obrázok traktora TODO: vykríčníky pri boxoch 3 3 3

První pokus – Statická třída class Singleton {     Singleton() = delete; public:     static void doSomething() {         // Useful code      } }; static class Singleton {     public static void DoSomething()     {         // Useful code     } } C++ C# +  Zaručení jedné "instance"  Globální přístup -  Statické metody jsou nevirtuální 4 4 4

Druhý pokus – statická instance // Singleton.h class Singleton { private:   static Singleton instance_;   Singleton() {}; public:   static Singleton& getInstance() {     return instance_;   }   void doSomething() {     // Useful code   } }; C++ One Definition Rule // Singleton.cpp #include "Singleton.h" Singleton Singleton::instance_; 5 5 5

Druhý pokus – pořadí inicializace (C++) // Singleton.h class Singleton { private:   static Singleton instance_;   Singleton() {}; public:   static Singleton& getInstance() {     return instance_;   }   int doSomething() {     // Useful code   } };  Pořadí: global instance_ vs. instance_ global  Řešení: Inline static? Meyer's singleton // Singleton.cpp #include "Singleton.h" Singleton Singleton::instance_; // SomeFile.cpp #include "Singleton.h" int global = Singleton::getInstance().doSomething(); 6 6 6

Druhý pokus – statická instance // Singleton.h class Singleton { private:   static Singleton instance_;   Singleton() {}; public:   static Singleton& getInstance() {     return instance_;   }   void doSomething() {     // Useful code   } }; inline Singleton Singleton::instance_; C++ C++17 One Definition Rule // Singleton.cpp Singleton Singleton::instance_; 7 7 7

Druhý pokus – statická instance // Singleton.h class Singleton { private:   static Singleton instance_;   Singleton() {}; public:   static Singleton& getInstance() {     return instance_;   }   void doSomething() {     // Useful code   } }; inline Singleton Singleton::instance_; C++ class Singleton {   static Singleton instance =     new Singleton();   private Singleton() {};   public static Singleton Instance {     get { return instance; }   }   public void doSomething() {     // Useful code   public static void aux() { } C# - Instance je zkonstruována vždy - Nedefinované pořadí inicializace a destrukce +/-  Instance je zkonstruována před prvním přístupem k libovolné položce třídy  8 8 8

Třetí pokus – statický pointer (C++) class Singleton { private:   inline static Singleton *instance_ = nullptr;   Singleton() {}; public:   static Singleton& getInstance() {     if (instance_ == nullptr) {       instance_ = new Singleton;     }     return *instance_;   }   void doSomething() {     // Useful code }; +  lazy instanciace  syntaxe podobná jiným jazykům 9 9 9

Třetí pokus (C#) + Plně lazy instanciace Typ Lazy (.NET 4) class Singleton {   private Singleton() {}   public static Singleton Instance {     get { return Nested.Instance; }   }   private class Nested {     public static Singleton Instance =       new Singleton();   public void DoSomething() {     // Useful code   public static void aux() {     // Useful code } class Singleton {   private Singleton() {}   private static     Lazy<Singleton> instance =       new Lazy<Singleton> (       () => new Singleton());   public static Singleton Instance {     get { return instance.Value; }   }   public void DoSomething() {     // Useful code   public static void aux() {     // Useful code } + Plně lazy instanciace 10 10 10

Implementace v C++ se vším všudy class Singleton { private:   Singleton() { /* … */ }   ~Singleton() { /* … */ }   inline static Singleton* instance_ = nullptr; public:   static Singleton& getInstance() {     if (instance_ == nullptr)       instance_ = new Singleton();     return *instance_;   }   Singleton (const Singleton&) = delete;   Singleton& operator=(const Singleton&) = delete;   void doSomething() {     //doing something }; int main() {   Singleton::getInstance().doSomething(); } Privátní konstruktor a destruktor Smazání copy konstruktoru a assignment operatoru 11 11 11

Problémy ALE ! … Základní implementace je jednoduchá Multithreading  Jak předíst data race-um  Dědičnost  Destrukce ALE ! … 12 12 12

Singleton a více vláknové aplikace Fungující implementace C++  Meyersův singleton  C#  Statická proměnná ve vnořené třídě – statické konstruktory jsou thread-safe  Třída Lazy<T> - konstrukce je thread-safe public static Singleton getInstance() {   return Nested.instance; } class Nested {   public static Singleton instance =   new Singleton(); static Lazy<Singleton> instance =    new Lazy<Singleton> (() => new Singleton()); 13 13 13

Singleton a více vláknové aplikace class Singleton {   Singleton() {};   static Singleton* instance_; public:   static Singleton* getInstance() {     if (instance_ == nullptr) {       instance_ = new Singleton();     }     return instance_;   }      void doSomething() {     //doing something   ​} }; Problém: Data race  Řešení:  Zámky 14 14 14

První pokus (C++ multithreading) class Singleton { private:   Singleton() {}   inline static Singleton* instance_ = nullptr;   static std::mutex lock_; public:   static Singleton& getInstance() {     lock_.lock();     if (instance_ == nullptr)       instance_ = new Singleton();     lock_.unlock();     return *instance_;   } };  Zámky fungují, ale …  Zamykáme i pro zkonstruování instance  Řešení => double-checked locking pattern 15 15 15

Druhý pokus (C++ multithreading) class Singleton { private:   Singleton() {}   inline static Singleton* instance_ = nullptr;   static std::mutex lock_; public:   static Singleton& getInstance() {     if (instance_ == nullptr) {       lock_.lock();       if (instance_ == nullptr)         instance_ = new Singleton();       lock_.unlock();     }     return *instance_;   } }; Problém: Nový data race  Zápis do proměnné typu pointer v C++ NENÍ atomický 16 16 16

Třetí pokus (C++ multithreading) Pointer stačí obalit do std::atomic class Singleton { private:   Singleton() {}   inline static std::atomic<Singleton*> instance_ = nullptr;   static std::mutex lock_; public:   static Singleton& getInstance() {     if (instance_.load() == nullptr) {       lock_.lock();       if (instance_.load() == nullptr)         instance_.store(new Singleton());       lock_.unlock();     }     return *instance_;   } }; 17 17 17

První možnost (C++ dedičnost) class Singleton { protected:   Singleton() { }; public:   static Singleton& instance() {     if (instance_ == nullptr) {       if (Config::SingletonName == "MAGIC")         instance_ = new MagicSingleton();       else         instance_ = new MuggleSingleton();     }     return *instance_;   }   virtual void doSomething() = 0; }; class MagicSingleton : public Singleton { private:   MagicSingleton() : Singleton() {  }   friend class Singleton;   virtual void doSomething() { /* ... */ } Subclassy potřebují base konstruktor Rodič musí vědet o všech potomcích! Společné rozhraní Bázová třída musí být friend pro přístup k private konstruktoru 18 18 18

Druhá možnost (C++ dedičnost) class Singleton {   inline static Singleton* instance_ = nullptr;   static std::map<std::string, Singleton*> registry_; protected:   Singleton();   static Singleton* lookUp (const std::string & name);   void register (const std::string & name, Singleton* s); public:   static Singleton* instance() {     if (instance_ == nullptr)       instance_ = lookUp(Config::SingletonName);     return instance_;   } }; class MagicSingleton : public Singleton {   inline static MagicSingleton instance_;   MagicSingleton() {     register("MagicSingleton", &instance_);   }; Není typesafe Potomek se zaregistruje Potomci se instanciují vždy 19 19 19

Třetí možnost (C++ dedičnost) class Singleton {   inline static Singleton* instance_ = nullptr; protected:   Singleton(); public:   template <typename T>   static Singleton& instance() {     if (instance_ == nullptr)       instance_ = new T();     return *instance_;   } }; class MagicSingleton: public Singleton {   friend class Singleton;   MagicSingleton() {};   void doSomething() { … } int main() {   Singleton::instance<MagicSingleton>(). …; } Bázová třída musí být friend pro přístup k private konstruktoru Múžeme zatypedefovat 20 20 20

Destrukce Zodpovědnost za zrušení Kdy je objekt zrušen? mechanizmy jazyka C++ anebo uživatel jak se správně postarat o zrušení objektu pozor na memory, resource leaks Kdy je objekt zrušen? jaké je správně pořadí rušení objektů 21 21 21

Destrukce pštrosem Pštrosí řešení (leaking singleton, ostrich singleton) problém destrukce ignorovat statická paměť se uvolní automaticky při ukončení procesu jako každá kulturní třída by měl mít destruktor zápis do logu, uzavření spojení, odhlášení, ... lze vést diskuze o tom co je a co není leak (memory leak, resource leak) class Singleton { private:   Singleton() {}; inline static Singleton *instance_ = nullptr; public:   static Singleton& getInstance(); void doSomething(); }; Foto: Altrendo Travel, Getty Images 22 22 22

Klíčové slovo static v jazyce C++ Kde žijí statické data? namespace class function int i1 = 0; // constant, implicit static, // load-time class A {} A a1; // implicit static, load-time class C { static A a2; // load-time void f() { static int i2 = 0; // constant, load-time static C instance; // local static variable // initialized first time // control flow passes // through } }; Kdy jsou tato data inicializována? statické konstanty globální statické proměnné lokální statické proměnné Kdo se postará o následnou destrukci? funkce atexit() jakou mají přesně životnost 23 23 23

Funkce atexit( ) Odstraňování statických proměnných: LIFO – nejdříve se odstraní naposledy inicializované int atexit(void*(exit_function)()); při vytváření objektu se zaregistruje funkce pro zrušení při ukončení programu se postupně zavolají registrované funkce lokální statické proměnné jsou zničeny stejným způsobem, zachovávajícím pořadí Singleton& Singleton::instance() { extern void __constructSingleton(void* memory); extern void __destroySingleton(); static bool __initialized = false; static char __buffer[sizeof(Singleton)]; if (!__initialized) { __constructSingleton(__buffer); atexit(__destroySingleton); __initialized = true; } return *reinterpret_cast<Singleton*>(__buffer); Funkce generované kompilátorem Proměnné generované kompilátorem __buffer obsahuje Singleton Volání funkce __constructSingleton() zavolá konstruktor na paměti __buffer zaregistruje destrukci 24 24 24

Scott Meyers Scott Meyers místo operátoru new se použije statická lokální proměnná instanci nedržíme ve statickém ukazateli funkce vracející referenci na statický objekt ve funkci od C++11 thread-safe t. j. inicializace proběhne jenom jednou class Singleton { public: static Singleton& instance() { static Singleton inst; return inst; } Singleton(const Singleton&) = delete; Singleton& operator=(const Singleton&) = delete; private: Singleton() { /* ... */ } ~Singleton() { /* ... */ } }; int main(int argc, char** argv) { Singleton& s = Singleton::instance(); /* ... */ 2. Inicializace statického objektu pouze při prvním průchodu 4. Návrat zkonstruovaného objektu 3. Konstruktor objektu 6. Destruktor objektu 1. Zavolá se metoda 5. Konec programu, destrukce statických proměnných 25 25 25

Pořadí destrukce Dead reference problem: při nevhodném pořadí mohou vzniknout reference na neexistující objekty příklad: singletony Keyboard, Display, Log lazy singletony vytvoření instance Log pouze při chybě destrukce Logu by měla následovat až po destrukcích ostatních singletonů nebo aspoň poznat problém a slušně umřít Inicializace Keyboard Inicializace Display s chybou Inicializace Log a zapsání chyby Konec programu Destrukce Log Destrukce Display Destrukce Keyboard s chybou Reference neexistujícího objektu Log 26 26 26

Inicializace přesunuta do privátní metody Detekce mrtvé reference Detekce destruovaného objektu přidáme statický příznak, který změníme při destrukci class Singleton { public: static Singleton& instance() { if (instance_ == nullptr) { if (destroyed_) onDeadRef(); else create(); } return *instance_; Singleton(const Singleton&) = delete; Singleton& operator=(const Singleton&) = delete; private: static void create() { static Singleton inst; instance_ = &inst; void onDeadRef() { throw /*...*/ } Singleton() { /*...*/ } ~Singleton() { destroyed_ = true; instance_ = nullptr; static bool destroyed_; static Singleton* instance_; }; Detekce problému Inicializace přesunuta do privátní metody Nastavení zrušení Příznak zrušení 27 27 27

Fénix Detekce někdy nestačí co když chceme přistupovat k singletonu kdykoliv? znovuvytvoření při detekci zrušeného objektu příklad: Keyboard a Display obyčejné singletony, Log Fénix C++: paměť statických objektů zůstane alokována až do konce běhu programu problém: stav starého mrtvého Singletonu je navždy ztracen class Singleton { /* ... */ void killPhoenix(); }; void Singleton::onDeadRef() { create(); new(instance_) Singleton; atexit(killPhoenix); destroyed_ = false; } void Singleton::killPhoenix() { instance_->~Singleton(); zbytek třídy nezměněn při detekci zrušení se uloží reference na paměť zrušeného objektu placement new zavolání konstruktoru na daném místě v paměti registrace destruktoru fénixu explicitní zavolání destruktoru nelze volat delete! 28 28 28

Prioritní fronta na zabití Dlouhověkost Problémy Fénixe ztráta stavu, uložení, uzavření, ... Dependency Manager nutnost konstrukce všech závislostí Singleton s dlouhověkostí při vytváření singletonu priorita destrukce log bude mít větší dlouhověkost explicitní mechanismus destrukce objektů nelze použít destrukci řízenou kompilátorem - pouze dynamické objekty class CoolClass { /* ... */ }; class Keyboard { /* ... */ }; class Log { /* ... */ }; CoolClass* global_object(new CoolClass); template <typename T> void setLongevity(T* object, int longevity); int main(int argc, char** argv) { setLongevity(&Keyboard::instance(), 5); setLongevity(&Keyboard::instance(), 6); setLongevity(global_object, 6); /* ... */ } Mechanismus by měl fungovat na jakékoliv (dynamické) objekty Šablona pro nastavování dlouhověkosti Prioritní fronta na zabití Po ukončení programu se objekty zabíjejí v tomto pořadí 29 29 29

Implementace dlouhověkosti Prioritní fronta při stejných prioritách se chová jako zásobník t. j. zachová pořadí volání C++ pravidlo: dříve inicializované objekty se destruují později neexistuje společný předek, registrační funkce je šablona ukazatel na abstraktního předka šablon obsahujících ukazatel na objekt Virtuální držák Virtuální destruktor LifeTimeTracker virtual ~LifeTimeTracker() longevity Šablona instanciována a objekt vytvořen šablonou SetLongevity ConcreteLTT<T> ~ConcreteLTT() T ~T() delete obj; 30 30 30

Implementace dlouhověkosti class LifetimeTracker { public: LifetimeTracker(unsigned int x): longevity(x) {} virtual ~LifetimeTracker() = 0; friend inline bool Compare( unsigned int longevity, const LifetimeTracker* p) { return p->longevity_ > longevity; } private: unsigned int longevity; }; inline LifetimeTracker::~LifetimeTracker() {} typedef LifetimeTracker** TrackerArray; extern TrackerArray pTA; extern unsigned int elements; template <typename T> struct Deleter { static void DeleteIt(T* pObj) { delete pObj; virtuální držák umí zabíjet... ... a porovnávat stáří vlastní fronta na zabití způsob zabití defaultně delete, uživatel si jej může dodefinovat využitím parciální specializace Co bylo dříve - vejce nebo slepice? TrackerArray by se měl chovat jako Singleton kdo vyřeší problému singletonu u TrackerArray? 31 31

Policy Based Design Andrei Alexandrescu “Modern C++ Design” Policy funkční celok nezávislí na ostatných funkčných celkoch (tzv. navzájem orotogonální) Policy class konkrétní implementace policy Konkrétní objekt je pak sestaven z různých policy class template metaprogramming + vícenásobná dědičnost jako Builder pattern s fixním počtem atributů Výhody compile-time lehce rozšířitelné Nevýhody syntaktická správnost != sémantická správnost

Policy Based Design pro Singleton Creation policy new malloc dědičnost Lifetime policy podle pravidel jazyka => LIFO fénix dlouhověkost pštros … Threading model policy jedno vláknové více vláknové neportabilní, systémově specifické řešení // Policies have only static methods T* pObj = Creator<T>::Create(); Creator<T>::Destroy(pObj); void (*pDestructionFunction)(); ... Lifetime<T>::ScheduleDestruction(pDestructionFunction); Lifetime<T>::OnDeadReference();

Policy Based Design pro Singleton template < class T, template <class> class CreationPolicy = CreateUsingNew, template <class> class LifetimePolicy = DefaultLifetime, template <class> class ThreadingModel = SingleThreaded > class SingletonHolder { public: static T& Instance(); private: // Helpers static void DestroySingleton(); // Protection SingletonHolder(); ... // Data typedef ThreadingModel<T>::VolatileType InstanceType; // For threading model purposes static InstanceType* pInstance_; static bool destroyed_; };

Policy Based Design pro Singleton template <...> T& SingletonHolder<...>::Instance() { if (!pInstance_) { typename ThreadingModel<T>::Lock guard; if (destroyed_) { LifetimePolicy<T>::OnDeadReference(); destroyed_ = false; } pInstance_ = CreationPolicy<T>::Create(); LifetimePolicy<T>::ScheduleCall(&DestroySingleton); return *pInstance_;

Policy Based Design pro Singleton class A { /* ... */ }; typedef SingletonHolder<A, CreateUsingMalloc, Phoenix, MultiThreaded> SingleA; // from here on you use SingleA::Instance() class A { /* ... */ }; class Derived : public A { /* ... */ }; template <class T> struct MyCreator : public CreateUsingNew<T> { static T* Create() { return new Derived; } }; typedef SingletonHolder<A, StaticAllocator, MyCreator> SingleA;

Policy Based Design pro Singleton class KeyboardImpl { ... }; class DisplayImpl { ... }; class LogImpl { ... }; inline unsigned int GetLongevity(KeyboardImpl*) { return 1; } inline unsigned int GetLongevity(DisplayImpl*) { return 1; } inline unsigned int GetLongevity(LogImpl*) { return 2; } // The log has greater longevity typedef SingletonHolder<KeyboardImpl, SingletonWithLongevity> Keyboard; typedef SingletonHolder<DisplayImpl, SingletonWithLongevity> Display; typedef SingletonHolder<LogImpl, SingletonWithLongevity> Log;

Použití Možné použití Ale hlavně používat s rozumem: po celou dobu běhu může existovat pouze jedna instance daného objektu zajištění přístupu k sdílenému zdroji, ke kterému: může být přistupováno z různých častí systému může být přistupováno i z vícerých vláken Ale hlavně používat s rozumem: singleton reprezentuje stav, který je globální, sdílený a mutable – to se sebou přináší různé problémy (například u testování) bezpečné místo použití je proto u třídy, která neobsahuje stav přímo související se samotnou aplikací (například už vzpomínaný Logger) 38 38 38

Příklad problému Máme jedno připojení k databázi Ale přijde šéf... zatím všechno v pořádku void saveOrder(const Order& o) { // We will use our Singleton Database::instance().storeOrder(o); } /* ... */ void saveOrder(const Order& o) { if (order.local()) { Database::instance().storeOrder(o); } else { Database2::instance().storeOrder(o); } Ale přijde šéf... „Ukládejte zahraniční objednávky jinam.“ co teď? Singleton se velmi špatně rozšiřuje téměř každý pokus o řešení vede na tvorbu další instance možné řešení: abstrahujeme připojení k databázím do jiného objektu Singleton schovává závislosti nevíme jaké objekty ve skutečnosti používá částečné řešení: Dependency injection 39 39 39

Související návrhové vzory Abstract Factory, Builder, Prototype častá implementace pomocí singletonu Facade v případě potřeby pouze jednoho vstupu do systému State stavové objekty jsou často singletony 40 40 40