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++
Ať se postará někdo jiný, najmeme si programátory z Číny. Čuníkům vstup zakázán.
Přednáška 11 Jiří Šebesta
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.
● SWIG - Simplified Wrapper and Interface Generator ● + google a diskusní fóra ● nástroj zjednodušující (a sjednocující)
Č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
C# - struktury, výčtové typy, pole
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
Adapter. Adapter – pojem Součástka navržená k propojení dvou „nekompatibilních“ zařízení Definice slova podle Cambridge Advanced Learner's Dictionary:
C# - Exceptions (výjimky)
Objektové programování
Dynamická alokace, polymorfismus
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.
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
OSNOVA: a) Přetížení členských funkcí b) Dědičnost tříd Jiří Šebesta Ústav radioelektroniky, FEKT VUT v Brně Počítače a programování 2 pro obor EST BPC2E.
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é)
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í.
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.
Návrhový vzor Flyweight
Dynamické proměnné (1) Proměnné, jejichž počet a (nebo) velikost pa-měti využívané těmito proměnnými se v prů-běhu programu mění Dynamické proměnné lze.
Bridge.
C# přehled vlastností.
NÁZEV ŠKOLY: S0Š Net Office, spol. s r.o., Orlová-Lutyně
ZAL – 7. cvičení 2016.
Unit of Work vzor z P of EAA (Fowler) 1.
Singleton
Composite “Spojuj a panuj”.
Bridge.
Transkript prezentace:

Singleton 1 1 1

Co design pattern řeší GoF Proč jedna instance? Proč global access? Singleton – ensure a class only has one instance, and provide a global point of access to it Proč jedna instance? mít více instancí může být nežádoucí / zbytečné / nebezpečné Proč global access? časté použití z mnoha míst v programu Vhodné použití Database Connection Pool Logger Keyboard Factories ze vzoru Abstract Factory Pattern Herní prostředí – např. mapa ve hře 2 2 2

ALE ! … Obsah Základní implementace je nesmírně jednoduchá class Singleton { static Singleton instance = new Singleton(); Singleton() {} public static Singleton getInstance() { return instance; } public void doSomething() { //doing something Základní implementace je nesmírně jednoduchá Jak správně napsat Singleton implementace v C# / C++ se trochu liší kvůli specifikům těchto jazyků Více vláknové aplikace jak v programu s více vlákny zajistit jednu instanci Dědičnost jak se postavit k dědičnosti Destrukce jak vyřešit problém destrukce Závislosti a rozšiřitelnost jaké další problémy souvisejí s tímto vzorem ALE ! … 3 3 3

Jak může Singleton vypadat? První pokus + zaručení „jedné“ instance globální přístup - statická metoda nemůže být virtuální class Singleton { Singleton() = delete; public: static void doSomething() { //doing something }; static class Singleton { public static void doSomething() { //doing something } C++ C# 4 4 4

Třída se o jedinečnost své instance bude starat sama Jak může Singleton vypadat? Druhý pokus Třída se o jedinečnost své instance bude starat sama class Singleton { static Singleton instance_; Singleton() {}; public: static Singleton& getInstance() { return instance_; } void doSomething() { //doing something }; class Singleton { static Singleton instance = new Singleton(); Singleton() {} public static Singleton getInstance() { return instance; } public void doSomething() { //doing something C++ C# - instance je zkonstruována vždy nedefinované pořadí inicializace a destrukce +/- instance je zkonstruována až před prvním přístupem do třídy (ale bohužel i v případě, že například referencujeme jinou položku) 5 5 5

konstruktor Singletonu je private, musíme předat lambdu Jak může Singleton vypadat? Třetí pokus (C#) typ Lazy od .NET 4 konstruktor Singletonu je private, musíme předat lambdu class Singleton { Singleton() {} public static Singleton getInstance(){ return Nested.instance; } class Nested { public static Singleton instance = new Singleton(); public void doSomething() { //doing something class Singleton { static Lazy<Singleton> instance = new Lazy<Singleton> ( () => new Singleton()); public static Singleton getInstance() { return instance.Value; } public void doSomething() { //doing something + plně lazy instanciace všechny předchozí vlastnosti, které jsme po singletonu vyžadovali 6 6 6

Jak může Singleton vypadat? Třetí pokus (C++) instance zkonstruována až při prvním průchodu funkcí varianta preferovaná v literatuře (najdete také v GoF) Meyersův Singleton class Singleton { Singleton() {}; public: static Singleton& getInstance() { static Singleton instance; return instance; }; void doSomething() { //doing something class Singleton { Singleton() {}; static Singleton* instance_; public: static Singleton* getInstance() { if (instance_ == nullptr) instance_ = new Singleton(); return instance_; }; void doSomething() { //doing something + lazy instanciace + lazy instanciace řízení destrukce objektu syntaxe víceméně stejná jako u jiných jazyků 7 7 7

Implementace v C++ se vším všudy class Singleton { private: Singleton() { /* … */ }; ~Singleton() { /* … */ }; static Singleton* instance_; 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 Singleton* Singleton::instance_(nullptr); int main (int argc, int ** argv) { Singleton::getInstance()->doSomething(); /* … */ } konstruktor i destruktor jsou privátní instanci si spravuje třída sama lazy instanciace nezapomenout smazat copy assignment a copy constructor nezapomenout na statickou inicializaci uvnitř .cpp!! (One Definition Rule) jednoduchý příklad použití 8 8 8

Singleton a více vláknové aplikace Řešení: Zámky 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 races 9 9 9

Singleton a více vláknové aplikace Některé předchozí implementace tento problém nemají Meyersův singleton – v c++ máme zajištěno, že se statická proměnná inicializuje vždy v jednom vlákně C# statická proměnná ve vnořené třídě – opět máme zajištěnou konstrukci pouze jedním vláknem třída Lazy<T> - opět konstrukce se provádí v jednom vlákně static Singleton& getInstance() { static Singleton instance; return instance; }; public static Singleton getInstance(){ return Nested.instance; } class Nested { public static Singleton instance = new Singleton(); static Lazy<Singleton> instance = new Lazy<Singleton> (() => new Singleton()); 10 10 10

Singleton a více vláknové aplikace – první pokus Zámky fungují, ale … zamykáme i po zkonstruování instance řešení => double-checked locking pattern class Singleton { Singleton() {}; static Singleton* instance_; static std::mutex lock_; public: static Singleton* getInstance() { lock_.lock(); if (instance_ == nullptr) instance_ = new Singleton(); lock_.unlock(); return instance_; }; void doSomething() { //doing something 11 11 11

Double Checked Locking Pattern Singleton a více vláknové aplikace – druhý pokus Už správně? bohužel, C++ nám negarantuje, že je zápis do proměnné typu pointer atomický (jiné vlákno v ní může vidět libovolný mezistav) class Singleton { Singleton() {}; static Singleton* instance_; static std::mutex lock_; public: static Singleton* getInstance() { if (instance_ == nullptr) { lock_.lock(); if (instance_ == nullptr) instance_ = new Singleton(); lock_.unlock(); } return instance_; }; void doSomething() { //doing something Double Checked Locking Pattern Problém: Nový data race 12 12 12

Pro odstranění data race stačí pointer zabalit do std::atomic Singleton a více vláknové aplikace – třetí pokus class Singleton { Singleton() {}; static std::atomic<Singleton*> instance_; 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_; }; void doSomething() { //doing something Pro odstranění data race stačí pointer zabalit do std::atomic 13 13 13

Singleton a dědičnost – první možnost class Singleton { /* constructors, destructors, etc. */ 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 { friend class Singleton; virtual void doSomething() { /* ... */ } class MuggleSingleton : public Singleton { /* different implementation */ Vytvoří se požadovaná instance podle konfigurace programu Problém: rodič musí vědět o všech potomcích Společné rozhraní, které musí všichni potomci implementovat Aby mohla bázová třída vytvářet instance, musí být friend Implementace rozhraní 14 14 14

Singleton a dědičnost – druhá možnost Varianta uvedená také v GoF class Singleton { static Singleton* instance_; static std::map<const char*, Singleton*> registry_; protected: Singleton(); static Singleton* lookUp (const char* name); void register (const char* name, Singleton* s); public: static Singleton* instance() { if (instance_ == nullptr) { instance_ = lookUp(Config::SingletonName); } return instance_; }; class MagicSingleton: public Singleton { static MagicSingleton instance_; MagicSingleton() { /* … */ register("MagicSingleton", &instance_); Registr udržuje názvy potomků a pointery na jejich instance Registruje instanci potomka pod zadaným jménem Nalezne a vrátí instanci podle aktuální konfigurace programu Problém: pro každého potomka existuje instance, používáme však jen jednu z nich. Potomek se při vytvoření zaregistruje u rodiče 15 15 15

Singleton a dědičnost – třetí možnost class Singleton { static Singleton* instance_; protected: Singleton(); public: template <typename T> static Singleton* instance() { if (instance_ == nullptr) { instance_ = new T(); } return instance_; virtual void doSomething() = 0; }; class MagicSingleton: public Singleton { friend class Singleton; MagicSingleton() {}; void doSomething() { … }; int main() { Singleton::instance<MagicSingleton>()-> …; Skutečná instance se určí podle parametru šablony Konstruktor je private, opět musí být třída Singleton friend Problém: hardcoded Jednoduché použití 16 16 16

Destrukce Zodpovědnost za zrušení Kdy je objekt zrušen? 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ů Některé objekty je potřeba mít přístupné vždy. jak vyřešit situaci kdy už byl odstraněn ještě potřebný objekt 17 17 17

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) V čem je problém? destruktor se nikdy nezavolá ukládáme statický ukazatel, ne statický objekt Foto: Altrendo Travel, Getty Images 18 18 18

Destrukce Killer Idea: class SingletonKiller { public: void setSingleton(Singleton* instance) { m_instance = instance; } Singleton* getSingleton() { return m_instance; ~SingletonKiller() { delete m_instance; private: static Singleton* m_instance; }; class Singleton { static Singleton& instance(); Singleton(const Singleton&) = delete; Singleton& operator=(const Singleton&) = delete; Singleton(); ~Singleton(); static SingletonKiller singletonKiller; Singleton* SingletonKiller::m_instance = nullptr; SingletonKiller Singleton::singletonKiller; Idea: Ukazatel na Singleton zabalíme do třídy starající se o jeho destrukci. Kompilátor zruší statický objekt singletonKiller, který ve svém destruktoru zabíjí instanci objektu Singleton. 2. Destruktor killera Killer obsahuje ukazatel na náš singleton 3. Destruktor singletonu 1. Destrukce statické proměnné Singleton& Singleton::instance() { if (!singletonKiller.getSingleton()) { singletonKiller.setSingleton( new Singleton); } return *singletonKiller.getSingleton(); 19 19 19

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

Klíčové slovo static v jazyce C++ Kde žijí statické data? jakou mají přesně životnost Kdy jsou tato data inicializována? pořadí inicializace lokální statické proměnné Kdo se postará o následnou destrukci? 21 21 21

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

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

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 (!m_instance) { if (m_destroyed) throw /* ... */ else create(); } return *m_instance; Singleton(const Singleton&) = delete; Singleton& operator=(const Singleton&) = delete; private: static void create() { static Singleton inst; m_instance = &inst; Singleton() {...} ~Singleton() { m_destroyed = true; m_instance = nullptr; static bool m_destroyed; static Singleton* m_instance; }; Singleton* Singleton::m_instance = 0; bool Singleton::m_destroyed = false; Detekce problému Inicializace přesunuta do privátní metody Nastavení zrušení Příznak zrušení 24 24 24

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(m_instance) Singleton; atexit(killPhoenix); m_destroyed = false; } void Singleton::killPhoenix() { m_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! 25 25 25

Prioritní fronta na zabití Dlouhověkost Problémy Fénixe ztráta stavu, uložení, uzavření, ... nejasnost C++ standardů ohledně funkce atexit() 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 Mechanismus by měl fungovat na jakékoliv (dynamické) objekty class MagicSingleton { /* ... */ }; class CoolClass { /* ... */ }; CoolClass* m_global_object(new CoolClass); template <typename T> void setLongevity(T* object, int longevity); int main(int argc, char** argv) { setLongevity(&MagicSingleton::instance(), 5); setLongevity(m_global_object, 6); /* ... */ } Šablona pro nastavování dlouhověkosti Prioritní fronta na zabití Po ukončení programu se objekty zabíjejí v tomto pořadí 26 26 26

Implementace dlouhověkosti Prioritní fronta při stejných prioritách se chová jako zásobník 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; 27 27 27

vlastní fronta na zabití 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 lze i free, ... Co bylo dříve - vejce nebo slepice? TrackerArray by se měl chovat jako Singleton kdo vyřeší problému singletonu u TrackerArray? 28 28

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) 29 29 29

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

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