samotář | |
---|---|
jedináček | |
Typ | generování |
profesionálové | organizuje API; implicitně načte správné moduly ve správném pořadí; ponechává prostor pro druhý podobný objekt |
Mínusy | komplikuje testování, multithreading a sledování latence; singletony by na sobě neměly implicitně záviset |
Popsáno v Návrhové vzory | Ano |
Singleton je generativní návrhový vzor , který zaručuje, že v aplikaci s jedním vláknem bude existovat jediná instance určité třídy, a poskytuje k této instanci globální přístupový bod.
Třída má pouze jednu instanci a poskytuje k ní globální přístupový bod. Když se pokusíte vytvořit tento objekt , vytvoří se pouze v případě, že ještě neexistuje, jinak se vrátí odkaz na již existující instanci a nedojde k žádné nové alokaci paměti. Je nezbytné, aby bylo možné použít instanci třídy, protože v mnoha případech je k dispozici širší funkčnost. Například k popsaným komponentám třídy lze přistupovat prostřednictvím rozhraní , pokud je taková možnost podporována jazykem.
Někdy je potřeba globální „osamělý“ objekt – jmenovitě objekt ( ), a nikoli sada procedur, které nejsou spojeny s žádným objektem ( ): log().put("Test");logPut("Test");
Takové objekty lze také vytvořit během inicializace programu. To může vést k následujícím potížím:
Tato možnost blokuje metodu getInstance() bez ohledu na to, zda jsme vytvořili jednu instanci nebo ne. To zpomaluje program, pokud potřebujete často získat objekt Singleton z různých vláken.
public class Singleton { private static Singleton instance ; private Singleton () {}; public static synchronized Singleton getInstance () { if ( instance == null ) { instance = new Singleton (); } návrat instance ; } }Od PEP 0318 Archivováno 3. června 2020 na Wayback Machine :
Příklad Pythonu s dekorátory def singleton ( cls ): instance = {} def getinstance (): pokud cls není v instancích : instance [ cls ] = cls () return instance [ cls ] return getinstance @singleton class MyClass : ...Od PEP 0318 Archivováno 3. června 2020 na Wayback Machine :
Příklad Pythonu na MetaClasses třída MetaSingleton ( typ ): _instances = {} def __call__ ( cls , * args , ** kwargs ): pokud cls není v cls . _instance : cls . _instance [ cls ] = super ( MetaSingleton , cls ) . __call__ ( * args , ** kwargs ) return cls . _instance [ cls ] třída MyClass ( metaclass = MetaSingleton ): ...Následuje jedna z možných implementací vzoru Singleton v C++ (známý jako Myers singleton ), kde singleton je statický lokální objekt. Důležité je, že konstruktor třídy je deklarován jako private, což zabraňuje instanci třídy mimo její implementaci. Kromě toho jsou konstruktor kopírování a operátor přiřazení také deklarovány jako soukromé. Ty by měly být deklarovány, ale ne definovány, protože to umožňuje snadno zjistitelnou chybu propojení, pokud jsou náhodně volány z kódu. Všimněte si také, že výše uvedený příklad není bezpečný pro vlákna v C++03, abyste mohli pracovat s třídou z více vláken, musíte proměnnou chránit theSingleInstancepřed souběžným přístupem, například pomocí mutexu nebo kritické sekce . Nicméně v C++11 je Myers singleton bezpečný pro vlákna a bez zámku.
Příklad v C++ třída OnlyOne { veřejnost : statický OnlyOne & Instance () { static OnlyOne theSingleInstance ; return theSingleInstance ; } soukromé : OnlyOne (){} OnlyOne ( const OnlyOne & root ) = delete ; OnlyOne & operator = ( const OnlyOne & ) = delete ; };Další příklad implementace singletonu v C++ s možností dědění pro vytvoření rozhraní, jehož framework bude ve skutečnosti singleton. Životnost jednoho předmětu je pohodlně řízena pomocí mechanismu počítání referencí .
Příklad v C++ třídy Singleton { chráněno : statický Singleton * _self ; Singleton () {} virtuální ~ Singleton () {} veřejnost : statický Singleton * Instance () { pokud ( ! _self ) { _self = new Singleton (); } return _self ; } statický bool DeleteInstance () { jestliže ( _self ) { smazat_sebe ; _ _self = 0 ; vrátit true ; } vrátit false ; } }; Singleton * Singleton :: _self = 0 ;Nejjednodušší způsob, jak implementovat vláknově bezpečný a líný singleton, však vyžaduje .NET verze 4 nebo vyšší.
public sealed class Singleton { private static readonly Lazy < Singleton > instanceHolder = new Lazy < Singleton >(() => new Singleton ()); private Singleton () { ... } public static Singleton Instance { get { return instanceHolder . hodnota ; } } }Pro línou inicializaci Singletonu v C# se doporučuje použít typové konstruktory (statický konstruktor). CLR automaticky vyvolá konstruktor typu při prvním přístupu k typu, přičemž zachovává bezpečnost synchronizace vláken. Typový konstruktor je automaticky vygenerován překladačem a v něm jsou inicializována všechna pole typu (statická pole). Neměli byste explicitně nastavovat konstruktor typu, protože v tomto případě bude zavolán bezprostředně před voláním typu a kompilátor JIT nebude schopen použít optimalizaci (například pokud k prvnímu volání Singleton dojde ve smyčce) .
/// generic Singleton<T> (bezpečné pro vlákna pomocí generické třídy a líné inicializace) /// <typeparam name="T">Třída Singleton</typeparam> public class Singleton < T > kde T : class { /// Chráněný konstruktor je potřeba, aby se zabránilo vytvoření instance třídy Singleton. /// Bude volána ze soukromého konstruktoru zděděné třídy. chráněný Singleton () { } /// Továrna se používá k líné inicializaci instance třídy private sealed class SingletonCreator < S > kde S : class { //Použito Reflection k vytvoření instance třídy bez veřejného konstruktoru private static pouze pro čtení S instance = ( S ) typeof ( S ). GetConstructor ( BindingFlags . Instance | BindingFlags . NonPublic , null , nový typ [ 0 ], nový ParametrModifier [ 0 ]). Invoke ( null ); public static S CreatorInstance { get { return instance ; } } } public static T Instance { get { return SingletonCreator < T >. CreatorInstance ; } } } /// Použití veřejné třídy Singleton TestClass : Singleton < TestClass > { /// Volá chráněný konstruktor třídy Singleton private TestClass () { } public string TestProc () { return "Ahoj světe" ; } }Můžete také použít standardní implementaci Singleton zabezpečenou pomocí líné inicializace:
public class Singleton { /// Chráněný konstruktor je potřeba k zabránění vytvoření instance třídy Singleton protected Singleton () { } private sealed class SingletonCreator { private static pouze pro čtení Singleton instance = new Singleton (); public static Singleton Instance { get { return instance ; } } } public static Singleton Instance { get { return SingletonCreator . instance ; } } }Pokud nejsou potřeba žádné veřejné statické metody nebo vlastnosti (jiné než vlastnost Instance), lze použít zjednodušenou verzi:
public class Singleton { private static pouze pro čtení Singleton instance = new Singleton (); public static Singleton Instance { get { return instance ; } } /// Chráněný konstruktor je potřeba, aby se zabránilo vytvoření instance třídy Singleton chráněné Singleton () { } }Příklad líné inicializace
jmenný prostor Singleton { public class Singleton { private static Singleton instance ; public static Singleton Instance { get { return instance ?? ( instance = nový Singleton ()); } } chráněný Singleton () { } } }Pro Delphi 2005 a vyšší je vhodný následující příklad (není bezpečný pro vlákna):
Příklad Delphi typ TSingleton = class strict private class var Instance : TSingleton ; public class function NewInstance : TObject ; přepsat ; konec ; funkce třídy TSingleton . NewInstance : TObject ; begin if not Assigned ( Instance ) then Instance := TSingleton ( zděděná NewInstance ) ; Vysledek := Instance ; konec ;U dřívějších verzí byste měli přesunout kód třídy do samostatného modulu a Instancenahradit deklaraci deklarací globální proměnné v její sekci ( implementationpřed Delphi 7 včetně class varnebyly žádné sekce strict private).
Na základě továrního konstruktéra z dokumentace Dart
class Singleton { static final Singleton _singleton = Singleton . _interní (); továrna Singleton () { return _singleton ; } singleton . _interní (); }Standardní knihovna (Ruby 1.8 a vyšší) obsahuje modul Singleton, díky kterému je vytváření singletonů ještě jednodušší:
vyžadovat třídu 'singleton' Foo include Singleton end a = Foo . instance # Foo.new není k dispozici, k získání odkazu na (jedinou) # instanci třídy Foo použijte metodu Foo#instanceMožnost soukromé třídy:
package { public class Singleton { private static var _instance : Singleton ; public function Singleton ( privateClass : PrivateClass ) { } public static function getInstance () : Singleton { if ( ! _instance ) _instance = new Singleton ( new PrivateClass ()); return _instance ; } } } // Protože je třída deklarována ve stejném souboru mimo // balíček, může ji používat pouze třída Singleton. class PrivateClass { public function PrivateClass () { } }Vyvolání možnosti výjimky:
package { public class Singleton { public static const instance : Singleton = new Singleton (); public function Singleton () { // Boolean(Singleton) má hodnotu false, pokud je třída // vytvořena před provedením statického konstruktoru if ( Singleton ) throw new Error ( "Třída je singleton." ); } } }Možnost s přístupovou proměnnou:
balíček { public class MySingleton { private static var _instance : MySingleton ; // Přístup k proměnné private static var _isConstructing : Boolean ; public function MySingleton () { if ( ! _isConstructing ) throw new Error ( "Singleton, použijte MySingleton.instance" ); } public static function get instance () : MySingleton { if ( _instance == null ) { _isConstructing = true ; _instance = new MySingleton (); _isConstructing = false ; } return _instance ; } } }Výhody možnosti soukromé třídy:
Nevýhoda možnosti soukromé třídy:
Výhody možnosti výjimky:
Klasický přístup (Coffeescript ≠ 1,5)
instance třídy Singleton = nedefinovaný konstruktor : -> if instance ? vrátit instanci else instance = @ # Kód konstruktoru konzole . tvrdit ( nový Singleton je nový Singleton );Přístup založený na možnosti přístupu k funkci z jejího těla (Coffeescript ≠ 1.5)
class Singleton init = -> # konstruktor jako metoda soukromé třídy # Kód konstruktoru # ... # Nahraďte konstruktor a ponechte tento (@) init = => @ return @ # Skutečný konstruktér. Slouží k volání init # return musí být použit, jinak vrátí tento konstruktor (@): -> return init . použít ( @ , argumenty ) konzole . tvrdit ( nový Singleton je nový Singleton ) Poznámka: změna skutečného konstruktoru od sebe sama, tzn. konstruktor: -> Singleton = => @ nedá nic, protože ve výsledném kódu JavaScript konstruktor ukazuje na místní konstruktor Singleton, nikoli na třídu Singleton.Pokud však používáte jmenné prostory, pak je tato možnost možná:
ns = {} třída ns . Singleton konstruktor: -> # Kód konstruktoru ns.Singleton == > @ konzole . potvrdit ( nové ns . Singleton je nové ns . Singleton )Metoda založená na skrývání proměnných pomocí uzávěrů. Jako bonus - možnost deklarovat soukromé metody a vlastnosti, které budou dostupné jak konstruktoru, tak metodám "třídy".
const Singleton = ( function () { let instance ; // Soukromé metody a vlastnosti // Funkce konstruktoru Singleton () { if ( instance ) return instance ; instance = tento ; } // Public Methods Singleton . prototyp . test = funkce () {}; návrat Singleton ; })(); konzole . log ( new Singleton () === new Singleton ());Bez použití skrývání proměnných existuje jednoduché řešení založené na tom, že funkce Singleton je objekt. Nevýhodou je možnost změnit vlastnost instance mimo třídu:
function Singleton () { const instance = Singleton . instance ; if ( instance ) return instance ; singleton . instance = tento ; } singleton . prototyp . test = funkce () {}; konzole . log ( new Singleton () === new Singleton ());Nejkratší varianta.
const Singleton = new ( function () { const instance = this ; return function () { return instance ; }; })(); konzole . log ( new Singleton () === new Singleton ());Použití statických soukromých polí třídy JS:
class Singleton { static # onlyInstance = null ; konstruktor (){ if ( ! Singleton . # onlyInstance ){ Singleton . # onlyInstance = this ; } else { return Singleton . # onlyInstance ; } } } konzole . log ( new Singleton () === new Singleton ());singleton.h
@interface Singleton : NSObject { } + ( Singleton * ) sharedInstance ; @konecsingleton.m
@implementationSingleton _ static Singleton * _sharedInstance = nil ; + ( Singleton * ) sharedInstance { @synchronized ( self ) { if ( ! _sharedInstance ) { _sharedInstance = [[ Singleton alloc ] init ]; } } return _sharedInstance ; } @konecNebo (pouze pro OS X 10.6+, iOS 4.0+):
@implementationSingleton _ + ( Singleton * ) sharedInstance { static dispatch_once_t pred ; static Singleton * sharedInstance = nula ; dispatch_once ( & pred , ^ { sharedInstance = [[ self alloc ] init ]; }); return sharedInstance ; } @konecDesignové vzory | |
---|---|
Hlavní | |
Generativní | |
Strukturální | |
Behaviorální | |
Paralelní programování |
|
architektonický |
|
Java EE šablony | |
Jiné šablony | |
knihy | |
Osobnosti |