Loner (designmönster)

Den aktuella versionen av sidan har ännu inte granskats av erfarna bidragsgivare och kan skilja sig väsentligt från versionen som granskades den 15 november 2020; verifiering kräver 101 redigeringar .
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.

Syfte

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:

Fördelar

Nackdelar

Applikation

Användningsexempel

Implementeringsexempel

Java 1.6

Java 1.6 exempel: inga inre klasser (lat osynkroniserad implementering) public class Singleton { privat statisk Singleton - instans ; privat Singleton () {}; public static Singleton getInstance () { if ( instans == null ) { instans = new Singleton (); } returnera instans ; } }

Java

Java Exempel: Synchronized Accessor

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

Java

Java-exempel: ingen lat initiering, med hjälp av en statisk initialiserare public class Singleton { privat statisk Singleton - instans ; static { instans = new Singleton (); // Undantagshantering är möjlig i detta block } privat Singleton () {} public static Singleton getInstance () { return instans ; } }

Java 1.5

Java 1.5 exempel: Initialization on Demand Holder offentlig klass Singleton { privat Singleton () {} privat statisk klass SingletonHolder { public static final Singleton- instans = new Singleton (); } public static Singleton getInstance () { return SingletonHolder . instans ; } }

Java 1.5

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

Python

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

Python

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

C++

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 ;

C#

Exempel i C#

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

PHP 4

Exempel i PHP4 <?php class Singleton { function Singleton ( $directCall = true ) { if ( $directCall ) { trigger_error ( "Kan inte använda konstruktorn för att skapa Singleton-klassen. Använd statisk getInstance()-metod" , E_USER_ERROR ); } //TODO: Lägg till huvudkonstruktörskoden här } function & getInstance () { static $instance ; if ( ! är_objekt ( $instans ) ) { $klass = __KLASS__ ; $instans = ny $klass ( false ); } returnera $instans ; } } //användning $test = & Singleton :: getInstance (); ?>

PHP 5

Exempel i PHP5 <?php class Singleton { private static $instance ; // objektinstans privat funktion __construct (){ /* ... @return Singleton */ } // Skydda från skapande via ny Singleton privat funktion __clone () { /* ... @return Singleton */ } // Skydda från skapande via kloning av privat funktion __wakeup () { /* ... @return Singleton */ } // Skydda från skapande via unserialize public static function getInstance () { // Returnerar en enda instans av klassen. @return Singleton if ( tom ( self :: $instance ) ) { self :: $instance = new self (); } returnera själv :: $instans ; } offentlig funktion doAction () { } } /* Application */ Singleton :: getInstance () -> doAction (); // ?>

PHP 5.4

Exempel i PHP5.4 <?php trait Singleton { private static $instance = null ; privat funktion __construct () { /* ... @return Singleton */ } // Skydda från skapande via ny Singleton privat funktion __clone () { /* ... @return Singleton */ } // Skydda från skapande via klon privat function __wakeup () { /* ... @return Singleton */ } // Skydda från skapande via unserialize public static function getInstance () { return self :: $instance === null ? self :: $instance = new static () // Om $instance är 'null', skapa då ett objekt new self() : self :: $instance ; // Annars returnerar ett befintligt 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ökan */ $foo = foo :: getInstance (); $foo -> incBar (); var_dump ( $foo -> getBar ()); $foo = foo :: getInstance (); $foo -> incBar (); var_dump ( $foo -> getBar ()); ?>

Delphi

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

Dart

Dart exempel

Baserat på fabrikskonstruktören från Dart- dokumentationen

klass Singleton { static final Singleton _singleton = Singleton . _intern (); fabrik Singleton () { return _singleton ; } singel . _intern (); }

Io

Io exempel Singleton := Objekt klon Singleton clone := Singleton

Ruby

Exempel i Ruby klass Singleton def self . ny @instans || = superslut slut

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

Common Lisp

Exempel i Common Lisp ( defclass singleton-class () ;; metaclass som implementerar singleton-mekanismen (( instans :initform nil ))) ( defmethod validate -superclass (( class singleton-class ) ( superclass standard-class )) t ) ;;Tillåt singleton-klasser att ärva från normala klasser ( defmethod validate -superclass (( class singleton-class ) ( superclass singleton-class )) t ) ;;Tillåt singleton-klasser att ärva från andra singleton-klasser ( defmethod validate -superclass (( class standard-class ) ( superclass singleton-class )) noll ) ;;Förbjud vanliga klasser från att ärva från singlar ( 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

Exempel i VB.NET Modulprogram _ Sub Main () Dim T1 As Singleton = Singleton . getInstance T1 . värde = 1000 Dim T2 As Singleton = Singleton . getInstance Console . WriteLine ( T2 . Value ) Konsol . Läs () End Sub Slutmodul _ Public Class Singleton Offentligt värde som heltal 'Tillåt inte Protected Sub constructor New () End Sub Private NotInheritable Class SingletonCreator Private Shared ReadOnly m_instance As New Singleton () Public Shared ReadOnly Property Instance () As Singleton Get Return m_instance End Get End Property End Class Public Shared ReadOnly Property getInstance () Som Singleton Get Return SingletonCreator . Instance End Get End Property slutklass _

Perl

Perl exempel använd v5.10 ; _ använd strikt ; paket Singleton ; sub new { # Deklarerar en statisk variabel $instance # och returnerar den som ett resultat av att köra metoden new state $instance = bless {}; } huvudpaket ; _ min $a = Singleton -> new ; min $b = Singleton -> new ; säg "$a $b" ; # Referenser $a och $b pekar på samma objekt

Perl

Perl- exempel med oföränderligt objekt #!/usr/bin/perl -w använd funktionen "säg" ; använd strikt ; använd varningar ; paket Singleton { min $instans ; # klassinstans (statiskt fält) # -- ** konstruktor ** -- sub new { my $class = shift ; om inte ( $instance ) { # kontrollera om det redan finns en instans av klassen $instance = { # om inte, skapa en ny och skriv namnet på personen för att säga hej till det namn => shift , }; välsigna $instans , $klass ; } returnera $instans ; # returnera den enda instansen av vår klass } # -- ** hej ** -- sub hello { my ( $self ) = ( shift ); säg "Hej, $self->{name}" ; # låt oss säga hej till ägaren av detta objekt } } min $a = Singleton -> new ( 'Alex' ); # skapa en instans av en klass som heter Alex my $b = Singleton -> new ( 'Barney' ); # ... försöker nu skapa en annan instans för Barney $a -> hello (); # Hej, Alex # ja, hej Alex $b -> hej (); # Hej, Alex # oops, Barney, förlåt, vilket missförstånd...

ActionScript 3

ActionScript- exempel

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

  • Om du försöker använda konstruktorn direkt, kommer kompilatorn att fånga felet direkt. // Inte den enda fördelen med denna metod
  • Objektet skapas på begäran.

Nackdelen med privatklassalternativet:

  • Du kan ersätta den privata klassen med din egen med samma namn.

Fördelar med undantagsalternativet:

  • Mindre kod.

CoffeeScript

Exempel i CoffeeScript

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 )

JavaScript

JavaScript- exempel med inkapsling

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

Objective-C

Exempel i Objective-C

singelton.h

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

singelton.m

@implementationSingleton _ statisk Singleton * _sharedInstance = noll ; + ( Singleton * ) sharedInstance { @synchronized ( self ) { if ( ! _sharedInstance ) { _sharedInstance = [[ Singleton alloc ] init ]; } } returnera _sharedInstance ; } @slutet

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

Swift

Snabbt exempel klass Singleton { static let shared = Singleton () privat init () { } }

Scala, Kotlin

Exempel i Scala och Kotlin object Singleton {} // nyckelordet "object" skapar en klass som implementerar "singleton"-mönstret som standard

Se även

Litteratur

  • Alan Shalloway, James R. Trott Designmönster. Ett nytt tillvägagångssätt för objektorienterad design = Designmönster förklaras: Ett nytt perspektiv på objektorienterad design. - M .: "Williams", 2002. - S. 288. - ISBN 0-201-71594-5 .
  • Eric Freeman, Elizabeth Freeman. Designmönster = Head First Design Patterns. - St Petersburg. : Peter, 2011. - 656 sid. - ISBN 978-5-459-00435-9 .

Länkar

Anteckningar