enspænder | |
---|---|
Singleton | |
Type | genererer |
fordele | organiserer API'en; implicit indlæser de rigtige moduler i den rigtige rækkefølge; efterlader plads til et andet lignende objekt |
Minusser | komplicerer testning, multithreading og latenssporing; singletons bør ikke implicit afhænge af hinanden |
Beskrevet i Design Patterns | Ja |
En singleton er et generativt designmønster, der garanterer, at der vil være en enkelt forekomst af en bestemt klasse i en enkelt-trådsapplikation, og giver et globalt adgangspunkt til denne forekomst.
Klassen har kun én instans , og den giver et globalt adgangspunkt til den. Når du forsøger at oprette dette objekt , oprettes det kun, hvis det ikke allerede eksisterer, ellers returneres en reference til en allerede eksisterende instans, og der sker ingen ny hukommelsesallokering. Det er vigtigt, at det er muligt at bruge en instans af klassen, da der i mange tilfælde bliver bredere funktionalitet tilgængelig. For eksempel kan de beskrevne klassekomponenter tilgås via grænsefladen , hvis en sådan mulighed understøttes af sproget.
Et globalt "ensomt" objekt - nemlig et objekt ( ), og ikke et sæt procedurer, der ikke er knyttet til noget objekt ( ) - er nogle gange nødvendigt: log().put("Test");logPut("Test");
Sådanne objekter kan også oprettes under programinitialisering. Dette kan føre til følgende vanskeligheder:
Denne mulighed blokerer for metoden getInstance(), uanset om vi har oprettet en enkelt instans eller ej. Dette gør programmet langsommere, hvis du ofte har brug for at få et Singleton-objekt fra forskellige tråde.
public class Singleton { privat statisk Singleton instans ; privat Singleton () {}; public static synkroniseret Singleton getInstance () { if ( instans == null ) { instans = new Singleton (); } returnere instans ; } }Fra PEP 0318 Arkiveret 3. juni 2020 på Wayback Machine :
Python eksempel med dekoratører def singleton ( cls ): forekomster = {} def getinstance (): hvis cls ikke er i forekomster : forekomster [ cls ] = cls () returnerer forekomster [ cls ] returnerer getinstance @singleton klasse MyClass : ...Fra PEP 0318 Arkiveret 3. juni 2020 på Wayback Machine :
Python - eksempel på MetaClasses klasse MetaSingleton ( type ): _forekomster = {} def __call__ ( cls , * args , ** kwargs ): hvis cls ikke er i cls . _forekomster : cls . _instances [ cls ] = super ( MetaSingleton , cls ) . __call__ ( * args , ** kwargs ) returner cls . _forekomster [ cls ] klasse MyClass ( metaclass = MetaSingleton ): ...Det følgende er en mulig implementering af Singleton-mønsteret i C++ (kendt som Myers singleton ), hvor singletonen er et statisk lokalt objekt. Det vigtige er, at klassekonstruktøren er erklæret som private, hvilket forhindrer klassen i at blive instansieret uden for dens implementering. Derudover er kopikonstruktøren og opgaveoperatøren også erklæret private. Sidstnævnte bør deklareres, men ikke defineres, da dette giver mulighed for en let detekterbar sammenkoblingsfejl, hvis de ved et uheld kaldes fra kode. Bemærk også, at ovenstående eksempel ikke er trådsikkert i C++03, for at arbejde med en klasse fra flere tråde, skal du beskytte variablen theSingleInstancemod samtidig adgang, for eksempel ved at bruge en mutex eller en kritisk sektion . I C++11 er Myers singleton dog gevindsikker og låsefri.
Eksempel i C++ klasse OnlyOne { offentligt : statisk OnlyOne & Instance () { statisk OnlyOne theSingleInstance ; returnere SingleInstance ; } privat : Kun Én (){} OnlyOne ( const OnlyOne & root ) = slet ; OnlyOne & operator = ( const OnlyOne & ) = slet ; };Et andet eksempel på implementering af en singleton i C++ med mulighed for nedarvning for at skabe en grænseflade, hvis ramme faktisk vil være en singleton. Levetiden for et enkelt objekt styres bekvemt ved hjælp af referencetællemekanismen .
Eksempel i C++ klasse Singleton { beskyttet : statisk Singleton * _selv ; Singleton () {} virtuel ~ Singleton () {} offentligt : statisk Singleton * Forekomst () { hvis ( ! _selv ) { _selv = ny Singleton (); } returnere _selv ; } statisk bool DeleteInstance () { hvis ( _selv ) { slet_selv ; _ _selv = 0 ; returnere sandt ; } returnere falsk ; } }; Singleton * Singleton :: _selv = 0 ;Den enkleste måde at implementere en trådsikker og doven singleton på kræver dog .NET version 4 eller mere.
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ærdi ; } } }Til doven initialisering af en Singleton i C# anbefales det at bruge typekonstruktører (statisk konstruktør). CLR'en kalder automatisk typens konstruktør, første gang der tilgås typen, samtidig med at trådsynkroniseringssikkerheden opretholdes. Typekonstruktøren genereres automatisk af compileren, og alle felter af typen (statiske felter) initialiseres i den. Du bør ikke udtrykkeligt indstille typekonstruktøren, for i dette tilfælde vil den blive kaldt umiddelbart før typen kaldes, og JIT-kompileren vil ikke være i stand til at anvende optimeringen (f.eks. hvis det første kald til Singleton sker i en loop) .
/// generisk Singleton<T> (trådsikker ved brug af generisk klasse og doven initialisering) /// <typeparam name="T">Singleton class</typeparam> public class Singleton < T > hvor T : class { /// Den beskyttede konstruktør er nødvendig for at forhindre Singleton-klassen i at blive instansieret. /// Det vil blive kaldt fra den private konstruktør af den nedarvede klasse. beskyttet Singleton () { } /// En fabrik bruges til dovent initialisering af en klasseinstans privat forseglet klasse SingletonCreator < S > hvor S : klasse { //Bruges af Reflection til at instansiere en klasse uden en offentlig konstruktør privat statisk skrivebeskyttet S instans = ( S ) typeof ( S ) ). GetConstructor ( BindingFlags . Instance | BindingFlags . NonPublic , null , new Type [ 0 ], new ParameterModifier [ 0 ]). Påberåbe ( null ); public static S CreatorInstance { get { return instance ; } } } public static T Instance { get { return SingletonCreator < T >. CreatorInstance ; } } } /// Brug af Singleton public class TestClass : Singleton < TestClass > { /// Kalder den beskyttede konstruktør af Singleton-klassen private TestClass () { } public string TestProc () { return "Hello World" ; } }Du kan også bruge standard-trådsikker Singleton-implementering med doven initialisering:
public class Singleton { /// Den beskyttede konstruktør er nødvendig for at forhindre oprettelsen af en forekomst af den Singleton-klassebeskyttede Singleton () { } privat forseglet klasse SingletonCreator { private static readonly Singleton instans = new Singleton (); public static Singleton Instance { get { return instance ; } } } public static Singleton Instance { get { return SingletonCreator . Forekomst ; } } }Hvis der ikke er behov for nogen offentlige statiske metoder eller egenskaber (ud over egenskaben Instance), kan en forenklet version bruges:
public class Singleton { private static readonly Singleton instans = new Singleton (); public static Singleton Instance { get { return instance ; } } /// Den beskyttede konstruktør er nødvendig for at forhindre oprettelsen af en forekomst af den Singleton-klassebeskyttede Singleton () { } }Eksempel på doven initialisering
navneområde Singleton { public class Singleton { private static Singleton instans ; public static Singleton Instance { get { return instance ?? ( instans = ny Singleton ()); } } beskyttet Singleton () { } } }Til Delphi 2005 og nyere er følgende eksempel egnet (ikke trådsikkert):
Delphi eksempel type TSingleton = klasse streng privat klasse var Forekomst : TSingleton ; public class funktion NewInstance : TObject ; tilsidesætte ; ende ; klassefunktion TSingleton . _ NewInstance : TObject ; start , hvis ikke Assigned ( Instance ), så Instance := TSingleton ( arvet NewInstance ) ; Resultat := Forekomst ; ende ;For tidligere versioner bør du flytte klassekoden til et separat modul og Instanceerstatte erklæringen med en erklæring af en global variabel i dens sektion (der var ingen sektioner implementationfør Delphi 7 inklusive ). class varstrict private
Baseret på fabrikskonstruktøren fra Dart- dokumentationen
klasse Singleton { static final Singleton _singleton = Singleton . _intern (); fabrik Singleton () { return _singleton ; } singleton . _intern (); }Standardbiblioteket (Ruby 1.8 og nyere) inkluderer Singleton-modulet, som gør det endnu nemmere at oprette singletons:
kræver 'singleton' klasse Foo inkluderer Singleton end a = Foo . forekomst # Foo.new er ikke tilgængelig. For at få en reference til en (enkelt) # forekomst af Foo-klassen skal du bruge metoden Foo#instanceMulighed for privat klasse:
package { public class Singleton { private static var _instance : Singleton ; offentlig funktion Singleton ( privateClass : PrivateClass ) { } public static function getInstance () : Singleton { if ( ! _instance ) _instance = new Singleton ( ny PrivateClass ()); returner _forekomst ; } } } // Fordi klassen er erklæret i den samme fil uden for // pakken, kan kun Singleton-klassen bruge den. klasse PrivateClass { public function PrivateClass () { } }Kaster en undtagelsesmulighed:
pakke { public class Singleton { public static const instans : Singleton = new Singleton (); public function Singleton () { // Boolean(Singleton) er falsk, hvis klassen // instansieres før den statiske konstruktør udføres, hvis ( Singleton ) kaster ny fejl ( "Klasse er singleton." ); } } }Mulighed med adgangsvariabel:
pakke { offentlig klasse MySingleton { private static var _instance : MySingleton ; // Access variable private static var _isConstructing : Boolean ; public function MySingleton () { if ( ! _isConstructing ) throw new Error ( "Singleton, use MySingleton.instance" ); } public static function get instance () : MySingleton { if ( _instance == null ) { _isConstructing = true ; _instance = ny MinSingleton (); _isConstructing = falsk ; } returner _instans ; } } }Fordele ved muligheden for privat klasse:
Ulempen ved den private klasse mulighed:
Fordele ved undtagelsesmuligheden:
Klassisk tilgang (Coffeescript ≠ 1,5)
klasse Singleton instans = udefineret konstruktør: -> if instans ? returner instans andet instans = @ # Konstruktørkode konsol . hævde ( ny Singleton er ny Singleton );Fremgangsmåde baseret på evnen til at få adgang til en funktion fra dens krop (Coffeescript ≠ 1,5)
klasse Singleton init = -> # konstruktør som en privat klassemetode # Konstruktørkode # ... # Udskift konstruktøren, behold denne (@) init = => @ return @ # Rigtig konstruktør. Tjener til at kalde init # return skal bruges, ellers vil det returnere denne (@) constructor : -> return init . anvende ( @ , argumenter ) konsol . hævde ( ny Singleton er ny Singleton ) Bemærk: at ændre den rigtige konstruktør fra sig selv, dvs. konstruktør: -> Singleton = => @ vil ikke give noget, fordi i den resulterende JavaScript-kode peger konstruktøren på den lokale Singleton-konstruktør, ikke Singleton-klassen.Men hvis du bruger navnerum, er denne mulighed mulig:
ns = {} klasse ns . Singleton - konstruktør: -> # Konstruktørkode ns.Singleton == > @ konsol . hævde ( ny ns . Singleton er ny ns . Singleton )En metode baseret på at skjule variable ved hjælp af lukninger. Som en bonus - muligheden for at erklære private metoder og egenskaber, der vil være tilgængelige for både konstruktøren og "klassens" metoder.
const Singleton = ( funktion () { lad instans ; // Private metoder og egenskaber // Konstruktørfunktion Singleton ( ) { if ( forekomst ) returnerer forekomst ; instans = dette ; } // Offentlige metoder Singleton . prototype . test = funktion () {}; returnere Singleton ; })(); konsol . log ( ny Singleton () === ny Singleton ());Uden at bruge variabelskjul er der en simpel løsning baseret på, at Singleton-funktionen er et objekt. Ulempen er muligheden for at ændre instansegenskaben uden for klassen:
function Singleton () { const instans = Singleton . instans ; if ( instans ) returnere instans ; singleton . instans = dette ; } singleton . prototype . test = funktion () {}; konsol . log ( ny Singleton () === ny Singleton ());Den korteste mulighed.
const Singleton = ny ( funktion () { const instans = denne ; return funktion () { return instans ; }; })(); konsol . log ( ny Singleton () === ny Singleton ());Brug af statiske private felter i en JS-klasse:
klasse Singleton { static # onlyInstance = null ; konstruktør (){ if ( ! Singleton . # onlyInstance ){ Singleton . # onlyInstance = dette ; } andet { returner Singleton . # onlyInstance ; } } } konsol . log ( ny Singleton () === ny Singleton ());singleton.h
@interface Singleton : NSObject { } + ( Singleton * ) sharedInstance ; @endesingleton.m
@implementationSingleton _ statisk Singleton * _sharedInstance = nul ; + ( Singleton * ) sharedInstance { @synkroniseret ( selv ) { if ( ! _sharedInstance ) { _sharedInstance = [[ Singleton alloc ] init ]; } } returner _sharedInstance ; } @endeEller (kun for OS X 10.6+, iOS 4.0+):
@implementationSingleton _ + ( Singleton * ) sharedInstance { static dispatch_once_t pred ; statisk Singleton * sharedInstance = nul ; dispatch_once ( & pred , ^ { sharedInstance = [[ selv alloc ] init ]; }); returner sharedInstance ; } @endeDesign mønstre | |
---|---|
Hoved | |
Generativ | |
Strukturel | |
Adfærdsmæssigt | |
Parallel programmering |
|
arkitektonisk |
|
Java EE skabeloner | |
Andre skabeloner | |
Bøger | |
Personligheder |