enstöring | |
---|---|
Singleton | |
Sorts | alstrande |
fördelar | organiserar API; laddar implicit rätt moduler i rätt ordning; lämnar plats för ett andra liknande föremål |
Minus | komplicerar testning, multithreading och latensspårning; singlar bör inte implicit vara beroende av varandra |
Beskrivs i Design Patterns | Ja |
En singleton är ett generativt designmönster som garanterar att det kommer att finnas en enda instans av en viss klass i en enkeltrådad applikation och ger en global åtkomstpunkt till denna instans.
Klassen har bara en instans och den tillhandahåller en global åtkomstpunkt till den. När du försöker skapa det här objektet skapas det bara om det inte redan finns, annars returneras en referens till en redan existerande instans och ingen ny minnesallokering sker. Det är viktigt att det är möjligt att använda en instans av klassen, eftersom bredare funktionalitet i många fall blir tillgänglig. Till exempel kan de beskrivna klasskomponenterna nås via gränssnittet , om en sådan möjlighet stöds av språket.
Ett globalt "ensamt" objekt - nämligen ett objekt ( ), och inte en uppsättning procedurer som inte är associerade med något objekt ( ) - behövs ibland: log().put("Test");logPut("Test");
Sådana objekt kan också skapas under programinitiering. Detta kan leda till följande svårigheter:
Det här alternativet blockerar metoden getInstance(), oavsett om vi har skapat en enskild instans eller inte. Detta saktar ner programmet om du behöver hämta ett Singleton-objekt från olika trådar ofta.
public class Singleton { privat statisk Singleton - instans ; privat Singleton () {}; public static synchronized Singleton getInstance () { if ( instans == null ) { instans = new Singleton (); } returnera instans ; } }Från PEP 0318 Arkiverad 3 juni 2020 på Wayback Machine :
Pythonexempel med dekoratörer def singleton ( cls ): instanser = {} def getinstance (): om cls inte i instanser : instanser [ cls ] = cls () returnera instanser [ cls ] returnera getinstance @singleton class MyClass : ...Från PEP 0318 Arkiverad 3 juni 2020 på Wayback Machine :
Python - exempel på MetaClasses klass MetaSingleton ( typ ): _instanser = {} def __call__ ( cls , * args , ** kwargs ): om cls inte i cls . _instanser : cls . _instanser [ cls ] = super ( MetaSingleton , cls ) . __call__ ( * args , ** kwargs ) returnerar cls . _instanser [ cls ] klass MyClass ( metaclass = MetaSingleton ): ...Följande är en möjlig implementering av Singleton-mönstret i C++ (känd som Myers singleton ), där singeltonen är ett statiskt lokalt objekt. Det viktiga är att klasskonstruktören deklareras som private, vilket förhindrar att klassen instansieras utanför dess implementering. Dessutom förklaras även kopiekonstruktören och uppdragsoperatören privata. De senare bör deklareras, men inte definieras, eftersom detta möjliggör ett lätt upptäckbart länkfel om de av misstag anropas från kod. Observera också att exemplet ovan inte är trådsäkert i C++03, för att arbeta med en klass från flera trådar måste du skydda variabeln theSingleInstancefrån samtidig åtkomst, till exempel genom att använda en mutex eller en kritisk sektion . Men i C++11 är Myers singelton gängsäker och låsfri.
Exempel i C++ klass OnlyOne { offentliga : statisk OnlyOne & Instance () { statisk OnlyOne theSingleInstance ; returnera SingleInstance ; } privat : OnlyOne (){} OnlyOne ( const OnlyOne & root ) = radera ; OnlyOne & operator = ( const OnlyOne & ) = radera ; };Ett annat exempel på implementeringen av en singleton i C ++ med möjlighet till arv för att skapa ett gränssnitt, vars ramverk kommer att vara en singleton. Livslängden för ett enskilt objekt styrs bekvämt med hjälp av referensräknemekanismen .
Exempel i C++ klass Singleton { skyddad : statisk Singleton * _self ; Singleton () {} virtuell ~ Singleton () {} offentliga : statisk Singleton * Instans () { om ( ! _själv ) { _self = new Singleton (); } returnera _self ; } statisk bool DeleteInstance () { om ( _själv ) { radera_själv ; _ _self = 0 ; returnera sant ; } returnera falskt ; } }; Singleton * Singleton :: _self = 0 ;Det enklaste sättet att implementera en trådsäker och lat singel kräver dock .NET version 4 eller mer.
public sealed class Singleton { private static readonly Lazy < Singleton > instanceHolder = new Lazy < Singleton >(() => new Singleton ()); privat Singleton () { ... } public static Singleton Instance { get { return instanceHolder . värde ; } } }För lat initiering av en Singleton i C#, rekommenderas att använda typkonstruktorer (statisk konstruktor). CLR:n anropar automatiskt typens konstruktör första gången typen används, samtidigt som trådsynkroniseringssäkerheten bibehålls. Typkonstruktorn genereras automatiskt av kompilatorn och alla fält av typen (statiska fält) initieras i den. Du bör inte uttryckligen ställa in typkonstruktorn, eftersom den i det här fallet kommer att anropas omedelbart innan typen anropas och JIT-kompilatorn kommer inte att kunna tillämpa optimeringen (till exempel om det första anropet till Singleton sker i en loop) .
/// generisk Singleton<T> (trådsäker med generisk klass och lat initialisering) /// <typeparam name="T">Singleton class</typeparam> public class Singleton < T > där T : class { /// Den skyddade konstruktorn behövs för att förhindra att Singleton-klassen instansieras. /// Det kommer att anropas från den privata konstruktören av den ärvda klassen. skyddad Singleton () { } /// En fabrik används för att lattigt initiera en klassinstans privat förseglad klass SingletonCreator < S > där S : class { //Används av Reflection för att instansiera en klass utan en offentlig konstruktor privat statisk skrivskyddad S instans = ( S ) typ av ( S ) ). GetConstructor ( BindingFlags . Instance | BindingFlags . NonPublic , null , new Type [ 0 ], new ParameterModifier [ 0 ]). Åberopa ( null ); public static S CreatorInstance { get { return instans ; } } } public static T Instance { get { return SingletonCreator < T >. CreatorInstance ; } } } /// Använda Singleton public class TestClass : Singleton < TestClass > { /// Anropar den skyddade konstruktören av Singleton-klassen private TestClass () { } public string TestProc () { return "Hello World" ; } }Du kan också använda den vanliga trådsäkra Singleton-implementeringen för lazy-initialisering:
public class Singleton { /// Den skyddade konstruktorn behövs för att förhindra skapandet av en instans av den Singleton- klassskyddade Singleton () { } privat förseglad klass SingletonCreator { privat statisk skrivskyddad Singleton - instans = ny Singleton (); public static Singleton Instance { get { return instans ; } } } public static Singleton Instance { get { return SingletonCreator . Instans ; } } }Om det inte finns något behov av några offentliga statiska metoder eller egenskaper (andra än Instance-egenskapen), kan en förenklad version användas:
public class Singleton { private static readonly Singleton - instans = new Singleton (); public static Singleton Instance { get { return instans ; } } /// Den skyddade konstruktorn behövs för att förhindra skapandet av en instans av den Singleton- klassskyddade Singleton () { } }Exempel på lat initialisering
namnområde Singleton { public class Singleton { privat statisk Singleton instans ; public static Singleton Instance { get { return instans ?? ( instans = ny Singleton ()); } } skyddad Singleton () { } } }För Delphi 2005 och högre är följande exempel lämpligt (inte gängsäkert):
Delphi exempel typ TSingleton = klass strikt privat klass var Instans : TSingleton ; public class funktion NewInstance : TObject ; åsidosätta ; slut ; klassfunktion TSingleton . _ NewInstance : TObject ; börja om inte Assigned ( Instance ) så Instance := TSingleton ( ärvd NewInstance ) ; Resultat := Instans ; slut ;För tidigare versioner bör du flytta klasskoden till en separat modul och Instanceersätta deklarationen med en deklaration av en global variabel i dess avsnitt (det fanns inga avsnitt implementationföre Delphi 7 inklusive ). class varstrict private
Baserat på fabrikskonstruktören från Dart- dokumentationen
klass Singleton { static final Singleton _singleton = Singleton . _intern (); fabrik Singleton () { return _singleton ; } singel . _intern (); }Standardbiblioteket (Ruby 1.8 och högre) inkluderar Singleton-modulen, vilket gör det ännu enklare att skapa singlar:
kräver 'singleton' klass Foo inkluderar Singleton end a = Foo . instans # Foo.new är inte tillgänglig, för att få en referens till en (enskild) # instans av Foo-klassen, använd metoden Foo#instanceAlternativ för privatklass:
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 ()); returnera _instans ; } } } // Eftersom klassen deklareras i samma fil utanför // paketet kan endast Singleton-klassen använda den. class PrivateClass { public function PrivateClass () { } }Kasta ett undantagsalternativ:
paket { public class Singleton { public static const instans : Singleton = new Singleton (); public funktion Singleton () { // Boolean(Singleton) är falsk om klassen // instansieras innan den statiska konstruktorn exekveras om ( Singleton ) throw new Error ( "Klass är singleton." ); } } }Alternativ med åtkomstvariabel:
paket { offentlig klass MySingleton { private static var _instance : MySingleton ; // Access variabel private static var _isConstructing : Boolean ; public function MySingleton () { if ( ! _isConstructing ) throw new Error ( "Singleton, använd MySingleton.instance" ); } public static function get instans () : MySingleton { if ( _instance == null ) { _isConstructing = true ; _instance = ny MySingleton (); _isConstructing = false ; } returnera _instans ; } } }Fördelar med alternativet privatklass:
Nackdelen med privatklassalternativet:
Fördelar med undantagsalternativet:
Klassiskt tillvägagångssätt (Coffeescript ≠ 1,5)
klass Singleton - instans = odefinierad konstruktor: -> if instans ? returnera instans annan instans = @ # Konstruktörskod konsol . hävda ( ny Singleton är ny Singleton );Tillvägagångssätt baserad på förmågan att komma åt en funktion från dess kropp (Coffeescript ≠ 1,5)
klass Singleton init = -> # konstruktor som en privat klassmetod # Konstruktorkod # ... # Byt ut konstruktorn, behåll denna (@) init = => @ return @ # Riktig konstruktör. Fungerar för att anropa init # return måste användas, annars returnerar den denna (@) konstruktor: -> return init . tillämpa ( @ , argument ) konsol . hävda ( ny Singleton är ny Singleton ) Obs: ändra den verkliga konstruktorn från sig själv, dvs. konstruktör: -> Singleton = => @ kommer inte att ge något, eftersom i den resulterande JavaScript-koden pekar konstruktorn på den lokala Singleton-konstruktorn, inte Singleton-klassen.Men om du använder namnutrymmen är det här alternativet möjligt:
ns = {} klass ns . Singleton - konstruktör: -> # Konstruktörskod ns.Singleton == > @ konsol . hävda ( ny ns . Singleton är ny ns . Singleton )En metod som bygger på att dölja variabler med hjälp av stängningar. Som en bonus - möjligheten att deklarera privata metoder och egenskaper som kommer att vara tillgängliga för både konstruktorn och "klass"-metoderna.
const Singleton = ( function () { låt instans ; // Privata metoder och egenskaper // Konstruktorfunktion Singleton ( ) { if ( instans ) returnerar instans ; instans = detta ; } // Public Methods Singleton . prototyp . test = funktion () {}; returnera Singleton ; })(); konsol . log ( new Singleton () === new Singleton ());Utan att använda variabeldöljning finns det en enkel lösning som bygger på att Singleton-funktionen är ett objekt. Nackdelen är möjligheten att ändra instansegenskapen utanför klassen:
function Singleton () { const instans = Singleton . instans ; if ( instans ) returnera instans ; singel . instans = detta ; } singel . prototyp . test = funktion () {}; konsol . log ( new Singleton () === new Singleton ());Det kortaste alternativet.
const Singleton = new ( function () { const instans = this ; return function () { return instans ; }; })(); konsol . log ( new Singleton () === new Singleton ());Använda statiska privata fält i en JS-klass:
class Singleton { static # onlyInstance = null ; konstruktor (){ if ( ! Singleton . # onlyInstance ){ Singleton . # onlyInstance = detta ; } annat { returnera Singleton . # onlyInstance ; } } } konsol . log ( new Singleton () === new Singleton ());singelton.h
@interface Singleton : NSObject { } + ( Singleton * ) sharedInstance ; @slutetsingelton.m
@implementationSingleton _ statisk Singleton * _sharedInstance = noll ; + ( Singleton * ) sharedInstance { @synchronized ( self ) { if ( ! _sharedInstance ) { _sharedInstance = [[ Singleton alloc ] init ]; } } returnera _sharedInstance ; } @slutetEller (endast för OS X 10.6+, iOS 4.0+):
@implementationSingleton _ + ( Singleton * ) sharedInstance { static dispatch_once_t pred ; statisk Singleton * sharedInstance = noll ; dispatch_once ( & pred , ^ { sharedInstance = [[ self alloc ] init ]; }); returnera sharedInstance ; } @slutetDesign mönster | |
---|---|
Main | |
Generativ | |
Strukturell | |
Beteende | |
Parallell programmering |
|
arkitektonisk |
|
Java EE-mallar | |
Andra mallar | |
Böcker | |
Personligheter |