Loner (designmønster)

Den aktuelle version af siden er endnu ikke blevet gennemgået af erfarne bidragydere og kan afvige væsentligt fra den version , der blev gennemgået den 15. november 2020; verifikation kræver 101 redigeringer .
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.

Formål

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:

Fordele

Ulemper

Ansøgning

Eksempler på brug

Implementeringseksempler

Java 1.6

Java 1.6 eksempel: ingen indre klasser (doven usynkroniseret implementering) public class Singleton { privat statisk Singleton instans ; privat Singleton () {}; public static Singleton getInstance () { if ( instans == null ) { instans = new Singleton (); } returnere instans ; } }

Java

Java Eksempel: Synchronized Accessor

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 ; } }

Java

Java-eksempel: ingen doven initialisering, ved hjælp af en statisk initialisering public class Singleton { privat statisk Singleton instans ; static { instance = new Singleton (); // Undtagelseshåndtering er mulig i denne blok } privat Singleton () {} public static Singleton getInstance () { return instance ; } }

Java 1.5

Java 1.5 eksempel: Initialization on Demand Holder offentlig klasse Singleton { privat Singleton () {} private static class SingletonHolder { public static final Singleton instans = new Singleton (); } public static Singleton getInstance () { return SingletonHolder . instans ; } }

Java 1.5

Java 1.5 eksempel: Enum singleton public enum SingletonEnum { INSTANCE ; public void someMethod () { *** } public void anotherMethod () { *** } }

Python

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 : ...

Python

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 ): ...

C++

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 ;

C#

Eksempel i C#

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 () { } } }

PHP 4

Eksempel i PHP4 <?php class Singleton { function Singleton ( $directCall = true ) { if ( $directCall ) { trigger_error ( "Kan ikke bruge konstruktør til at oprette Singleton-klasse. Brug statisk getInstance() metode" , E_USER_ERROR ); } //TODO: Tilføj hovedkonstruktørkoden her } function & getInstance () { static $instance ; if ( ! er_objekt ( $forekomst ) ) { $klasse = __KLASSE__ ; $instans = ny $klasse ( false ); } returner $instance ; } } //usage $test = & Singleton :: getInstance (); ?>

PHP 5

Eksempel i PHP5 <?php class Singleton { private static $instance ; // objektforekomst privat funktion __construct (){ /* ... @return Singleton */ } // Beskyt mod oprettelse via ny Singleton privat funktion __clone () { /* ... @return Singleton */ } // Beskyt mod oprettelse via kloning af privat funktion __wakeup () { /* ... @return Singleton */ } // Beskyt mod oprettelse via unserialize offentlig statisk funktion getInstance () { // Returnerer en enkelt forekomst af klassen. @return Singleton if ( tom ( self :: $instance ) ) { self :: $instance = new self (); } returner selv :: $forekomst ; } offentlig funktion doAction () { } } /* Application */ Singleton :: getInstance () -> doAction (); // ?>

PHP 5.4

Eksempel i PHP5.4 <?php trait Singleton { private static $instance = null ; privat funktion __construct () { /* ... @return Singleton */ } // Beskyt mod oprettelse via ny Singleton privat funktion __clone () { /* ... @return Singleton */ } // Beskyt mod oprettelse via klon privat funktion __wakeup () { /* ... @return Singleton */ } // Beskyt mod oprettelse via unserialize public static function getInstance () { return self :: $instance === null ? self :: $instance = new static () // Hvis $instance er 'null', så opret et objekt new self() : self :: $instance ; // Ellers returnerer et eksisterende objekt } } /** * Class Foo * @method static Foo getInstance() */ class Foo { use Singleton ; privat $bar = 0 ; public function incBar () { $this -> bar ++ ; } public function getBar () { return $this -> bar ; } } /* Ansøgning */ $foo = foo :: getInstance (); $foo -> incBar (); var_dump ( $foo -> getBar ()); $foo = foo :: getInstance (); $foo -> incBar (); var_dump ( $foo -> getBar ()); ?>

Delphi

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

Dart

Dart eksempel

Baseret på fabrikskonstruktøren fra Dart- dokumentationen

klasse Singleton { static final Singleton _singleton = Singleton . _intern (); fabrik Singleton () { return _singleton ; } singleton . _intern (); }

Io

Io eksempel Singleton := Objekt klon Singleton klon := Singleton

Ruby

Eksempel i Ruby klasse Singleton def self . ny @instans ||= super end end

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#instance

Common Lisp

Eksempel i Common Lisp ( defclass singleton-class () ;; metaclass, der implementerer singleton-mekanismen (( instans :initform nil ))) ( defmethod validate- superclass (( klasse singleton-class ) ( superclass standard-class )) t ) ;; Tillad singleton-klasser at arve fra normale klasser ( defmethod validate- superclass (( klasse singleton-class ) ( superclass singleton-class )) t ) ;; Tillad singleton-klasser at arve fra andre singleton-klasser ( defmethod validate- superclass (( class standard-class ) ( superclass singleton-class )) nil ) ;;Forbyd almindelige klasser at arve fra singletons ( defmethod make-instance (( class singleton-class ) &key ) ( with-slots ( instans ) class ( eller instans ( setf instans ( call-next-method ))))) ( defclass my-singleton-class () () ( :metaclass singleton-class ))

VB.NET

Eksempel i VB.NET Modul program Sub Main () Dim T1 Som Singleton = Singleton . getInstance T1 . værdi = 1000 Dim T2 Som Singleton = Singleton . getInstance Console . WriteLine ( T2 . Værdi ) Konsol . Læs () End Sub Slut modul Public Class Singleton Offentlig værdi som heltal 'Tillad ikke Protected Sub constructor New () End Sub Private NotInheritable Class SingletonCreator Private Shared ReadOnly m_instance As New Singleton () Offentlig Shared ReadOnly Property Instance () Som Singleton Get Return m_instance End Get End Property End Class Public Shared ReadOnly Property getInstance () Som Singleton Return SingletonCreator . Instance End Get End Property slutklasse _

Perl

Perl eksempel brug v5.10 ; _ brug streng ; pakke Singleton ; sub new { # Erklærer en statisk variabel $instance # og returnerer den som et resultat af udførelse af metoden new state $instance = bless {}; } hovedpakke ; _ min $a = Singleton -> new ; min $b = Singleton -> ny ; sig "$a $b" ; # Referencer $a og $b peger på det samme objekt

Perl

Perl eksempel med uforanderligt objekt #!/usr/bin/perl -w brug funktionen "sig" ; brug streng ; brug advarsler ; pakke Singleton { min $instans ; # klasseforekomst (statisk felt) # -- ** constructor ** -- sub new { my $class = shift ; medmindre ( $instance ) { # tjek om der allerede er en instans af klassen $instance = { # hvis ikke, opret en ny og skriv navnet på personen for at sige hej til dens navn => shift , }; velsigne $instans , $klasse ; } returner $instance ; # returner den eneste forekomst af vores klasse } # -- ** hej ** -- sub hello { my ( $selv ) = ( skift ); sig "Hej, $self->{navn}" ; # lad os sige hej til ejeren af ​​dette objekt } } min $a = Singleton -> new ( 'Alex' ); # opret en forekomst af en klasse ved navn Alex my $b = Singleton -> new ( 'Barney' ); # ... prøver nu at oprette en anden instans til Barney $a -> hello (); # Hej, Alex # ja, hej Alex $b -> hej (); # Hej Alex # ups, Barney, undskyld, sikke en misforståelse...

ActionScript 3

ActionScript eksempel

Mulighed 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:

  • Hvis du prøver at bruge konstruktøren direkte, vil compileren fange fejlen med det samme. // Ikke den eneste fordel ved denne metode
  • Objektet oprettes på forespørgsel.

Ulempen ved den private klasse mulighed:

  • Du kan erstatte privatklassen med din egen med samme navn.

Fordele ved undtagelsesmuligheden:

  • Mindre kode.

CoffeeScript

Eksempel i CoffeeScript

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 )

JavaScript

JavaScript eksempel med indkapsling

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 ());

Objective-C

Eksempel i Objective-C

singleton.h

@interface Singleton  : NSObject { } + ( Singleton * ) sharedInstance ; @ende

singleton.m

@implementationSingleton _ statisk Singleton * _sharedInstance = nul ; + ( Singleton * ) sharedInstance { @synkroniseret ( selv ) { if ( ! _sharedInstance ) { _sharedInstance = [[ Singleton alloc ] init ]; } } returner _sharedInstance ; } @ende

Eller (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 ; } @ende

Swift

Hurtigt eksempel klasse Singleton { static let shared = Singleton () privat init () { } }

Scala, Kotlin

Eksempel i Scala og Kotlin objekt Singleton {} // søgeordet "object" opretter en klasse, der implementerer "singleton"-mønsteret som standard

Se også

Litteratur

  • Alan Shalloway, James R. Trott Designmønstre. En ny tilgang til objektorienteret design = Designmønstre forklaret: Et nyt perspektiv på objektorienteret design. - M .: "Williams", 2002. - S. 288. - ISBN 0-201-71594-5 .
  • Eric Freeman, Elizabeth Freeman. Designmønstre = Head First Design Patterns. - Sankt Petersborg. : Peter, 2011. - 656 s. - ISBN 978-5-459-00435-9 .

Links

Noter