Loner (model de design)

Versiunea actuală a paginii nu a fost încă examinată de colaboratori experimentați și poate diferi semnificativ de versiunea revizuită pe 15 noiembrie 2020; verificarea necesită 101 editări .
singuratic
Singleton
Tip de generatoare
pro organizează API-ul; încarcă implicit modulele potrivite în ordinea corectă; lasă loc unui al doilea obiect similar
Minusuri complică testarea, multithreadingul și urmărirea latenței; singletons nu ar trebui să depindă implicit unul de celălalt
Descris în Design Patterns da

Un  singleton este un model de design generativ care garantează că va exista o singură instanță a unei anumite clase într-o aplicație cu un singur thread și oferă un punct de acces global la această instanță.

Scop

Clasa are o singură instanță și oferă un punct de acces global la aceasta. Când încercați să creați acest obiect , acesta este creat numai dacă nu există deja, altfel se returnează o referință la o instanță deja existentă și nu are loc o nouă alocare de memorie. Este esențial să fie posibilă utilizarea unei instanțe a clasei, deoarece în multe cazuri devin disponibile o funcționalitate mai largă. De exemplu, componentele clasei descrise pot fi accesate prin interfață , dacă o astfel de posibilitate este suportată de limbaj.

Un obiect „singuratic” global - și anume un obiect ( ), și nu un set de proceduri care nu sunt asociate cu niciun obiect ( ) - este uneori necesar: log().put("Test");logPut("Test");

Astfel de obiecte pot fi create și în timpul inițializării programului. Acest lucru poate duce la următoarele dificultăți:

Pro

Contra

Aplicație

Exemple de utilizare

Exemple de implementare

Java 1.6

Exemplu Java 1.6: fără clase interioare (implementare leneșă nesincronizată) public class Singleton { private static Singleton instance ; private Singleton () {}; public static Singleton getInstance () { if ( instance == null ) { instance = new Singleton (); } returnare instanță ; } }

Java

Exemplu Java: Accesor sincronizat

Această opțiune blochează metoda getInstance(), indiferent dacă am creat o singură instanță sau nu. Acest lucru încetinește programul dacă trebuie să obțineți frecvent un obiect Singleton din fire diferite.

public class Singleton { private static Singleton instance ; private Singleton () {}; public static sincronizat Singleton getInstance () { if ( instance == null ) { instance = new Singleton (); } returnare instanță ; } }

Java

Exemplu Java: fără inițializare leneșă, folosind un inițializator static public class Singleton { private static Singleton instance ; static { instance = new Singleton (); // Gestionarea excepțiilor este posibilă în acest bloc } singleton privat () {} public static Singleton getInstance () { return instance ; } }

Java 1.5

Exemplu Java 1.5: Deținător de inițializare la cerere clasă publică Singleton { private Singleton () {} private static class SingletonHolder { public static final Singleton instance = new Singleton (); } public static Singleton getInstance () { return SingletonHolder . instanță ; } }

Java 1.5

Exemplu Java 1.5: Enum singleton public enum SingletonEnum { INSTANŢĂ ; public void someMethod () { *** } public void anotherMethod () { *** } }

Python

Din PEP 0318 Arhivat 3 iunie 2020 la Wayback Machine :

Exemplu de piton cu decoratori def singleton ( cls ): instances = {} def getinstance (): dacă cls nu este în instanțe : instances [ cls ] = cls () return instances [ cls ] return getinstance @singleton class MyClass : ...

Python

Din PEP 0318 Arhivat 3 iunie 2020 la Wayback Machine :

Exemplu Python pe MetaClasses clasa MetaSingleton ( tip ): _instances = {} def __call__ ( cls , * args , ** kwargs ): dacă cls nu este în cls . _instanțe : cls . _instances [ cls ] = super ( MetaSingleton , cls ) . __call__ ( * args , ** kwargs ) return cls . _instanțe [ cls ] clasa MyClass ( metaclass = MetaSingleton ): ...

C++

Următoarea este o implementare posibilă a modelului Singleton în C++ (cunoscut sub numele de singleton Myers ), unde singletonul este un obiect local static. Punctul important este că constructorul clasei este declarat ca private, ceea ce împiedică instanțiarea clasei în afara implementării sale. În plus, constructorul de copiere și operatorul de atribuire sunt, de asemenea, declarate private. Acestea din urmă ar trebui să fie declarate, dar nu definite, deoarece acest lucru permite o eroare de legătură ușor detectabilă dacă sunt apelate accidental din cod. De asemenea, rețineți că exemplul de mai sus nu este sigur pentru fire în C++03, pentru a lucra cu o clasă din mai multe fire, trebuie să protejați variabila theSingleInstancede accesul concurent, de exemplu, folosind un mutex sau o secțiune critică . Cu toate acestea, în C++11 , singleton-ul Myers este sigur pentru fire și fără blocare.

Exemplu în C++ clasa OnlyOne { public : static OnlyOne și Instanță () { static OnlyOne theSingleInstance ; returneazăSingleInstance ; _ } privat : OnlyOne (){} OnlyOne ( const OnlyOne & root ) = șterge ; OnlyOne & operator = ( const OnlyOne & ) = delete ; };

Un alt exemplu de implementare a unui singleton în C++ cu posibilitatea de moștenire pentru a crea o interfață, al cărei cadru va fi, de fapt, un singleton. Durata de viață a unui singur obiect este controlată convenabil folosind mecanismul de numărare a referințelor .

Exemplu în C++ clasa Singleton { protejat : static Singleton * _self ; Singleton () {} virtual ~ Singleton () {} public : Singleton static * Instanță () { dacă ( ! _self ) { _self = nou Singleton (); } return _self ; } static bool DeleteInstance () { daca ( _sine ) { delete_self ; _ _self = 0 ; returnează adevărat ; } returnează fals ; } }; Singleton * Singleton :: _self = 0 ;

C#

Exemplu în C#

Cu toate acestea, cel mai simplu mod de a implementa un singleton sigur și leneș necesită .NET versiunea 4 sau mai mult.

public sealed class Singleton { private static readonly Lazy < Singleton > instanceHolder = new Lazy < Singleton >(() => new Singleton ()); private Singleton () { ... } public static Singleton Instance { get { return instanceHolder . valoare ; } } }

Pentru inițializarea leneșă a unui Singleton în C#, este recomandat să folosiți constructori de tip (constructor static). CLR invocă automat constructorul tipului prima dată când este accesat tipul, menținând în același timp siguranța sincronizării firului. Constructorul de tip este generat automat de compilator și toate câmpurile de tip (câmpuri statice) sunt inițializate în el. Nu ar trebui să setați explicit constructorul de tip, deoarece în acest caz va fi apelat imediat înainte ca tipul să fie apelat și compilatorul JIT nu va putea aplica optimizarea (de exemplu, dacă primul apel la Singleton are loc într-o buclă) .

/// generic Singleton<T> (securitate pentru fire folosind clasa generică și inițializarea leneșă) /// <typeparam name="T">Clasa Singleton</typeparam> clasă publică Singleton < T > unde T : clasa { /// Constructorul protejat este necesar pentru a preveni instanțiarea clasei Singleton. /// Va fi apelat de la constructorul privat al clasei moștenite. Singleton protejat () { } /// O fabrică este folosită pentru a inițializa leneș o instanță de clasă clasă privată sigilată SingletonCreator < S > unde S : class { // Folosită de Reflection pentru a instanția o clasă fără un constructor public privat static readonly S instance = ( S ) typeof ( S ) ). GetConstructor ( BindingFlags . Instanță | BindingFlags . NonPublic , null , nou Tip [ 0 ], nou ParameterModifier [ 0 ]). Invocare ( nul ); public static S CreatorInstance { get { return instance ; } } } public static T Instanță { get { return SingletonCreator < T >. CreatorInstance ; } } } /// Utilizarea clasei publice Singleton TestClass : Singleton < TestClass > { /// Apelează constructorul protejat al clasei Singleton Private TestClass () { } public șir TestProc () { return „Hello World” ; } }

Puteți utiliza, de asemenea, implementarea standard Singleton de inițializare leneră, sigură pentru fire:

clasă publică Singleton { /// Constructorul protejat este necesar pentru a preveni crearea unei instanțe a clasei Singleton protejată Singleton () { } private sealed class SingletonCreator { private static readonly Singleton instance = new Singleton (); public static Singleton Instance { get { return instance ; } } } public static Singleton Instance { get { return SingletonCreator . Instanță ; } } }

Dacă nu este nevoie de nicio metodă sau proprietăți statice publice (altele decât proprietatea Instanță), atunci poate fi utilizată o versiune simplificată:

public class Singleton { private static readonly Singleton instance = new Singleton (); public static Singleton Instance { get { return instance ; } } /// Constructorul protejat este necesar pentru a preveni crearea unei instanțe a clasei Singleton protejată Singleton () { } }

Exemplu de inițializare leneșă

namespace Singleton { public class Singleton { private static Singleton instance ; public static Singleton Instance { get { return instance ?? ( instanță = nou Singleton ()); } } Singleton protejat () { } } }

PHP 4

Exemplu în PHP4 <?php class Singleton { function Singleton ( $directCall = true ) { if ( $directCall ) { trigger_error ( "Nu se poate folosi constructorul pentru a crea clasa Singleton. Foloseste metoda static getInstance()" , E_USER_ERROR ); } //TODO: Adăugați aici codul constructorului principal } function & getInstance () { static $instanta ; if ( ! este_obiect ( $instanță ) ) { $clasă = __CLASS__ ; $instanta = $clasa noua ( false ); } return $instanta ; } } //utilizare $test = & Singleton :: getInstance (); ?>

PHP 5

Exemplu în PHP5 <?php class Singleton { private static $instanță ; // Instanța obiectului funcție privată __construct () { /* ... @return Singleton */ } // Protejează împotriva creării prin noua funcție privată Singleton __clone () { /* ... @return Singleton */ } // Protejează împotriva creare prin clonarea funcției private __wakeup () { /* ... @return Singleton */ } // Protejează împotriva creării prin deserializarea funcției publice statice getInstance () { // Returnează o singură instanță a clasei. @return Singleton if ( gol ( self :: $instanta ) ) { self :: $instanta = self nou (); } return self :: $instanta ; } funcția publică doAction () { } } /* Aplicație */ Singleton :: getInstance () -> doAction (); // ?>

PHP 5.4

Exemplu în PHP5.4 <?php caracteristică Singleton { private static $instanță = null ; funcția privată __construct () { /* ... @return Singleton */ } // Protejează împotriva creării prin noua funcție privată Singleton __clone () { /* ... @return Singleton */ } // Protejează împotriva creării prin clona privată function __wakeup () { /* ... @return Singleton */ } // Protejează împotriva creării prin unserialize public static function getInstance () { return self :: $instance === null ? self :: $instance = new static () // Daca $instance este 'null' atunci creeaza un obiect new self() : self :: $instance ; // Altfel returnează un obiect existent } } /** * Class Foo * @method static Foo getInstance() */ class Foo { use Singleton ; private $bar = 0 ; funcția publică incBar () { $this -> bar ++ ; } public function getBar () { return $this -> bar ; } } /* Aplicație */ $foo = foo :: getInstance (); $foo -> incBar (); var_dump ( $foo -> getBar ()); $foo = foo :: getInstance (); $foo -> incBar (); var_dump ( $foo -> getBar ()); ?>

Delphi

Pentru Delphi 2005 și versiuni ulterioare, următorul exemplu este potrivit (nu este sigur pentru fire):

exemplu Delphi tip TSingleton = clasă strict private class var Instanță : TSingleton ; funcție de clasă publică NewInstance : TObject ; suprascrie ; sfârşitul ; funcția de clasă TSingleton . NewInstance : TObject ; începe dacă nu este atribuită ( Instanță ) , atunci Instanță := TSingleton ( Instanță nouă moștenită ) ; Rezultat := Instanță ; sfârşitul ;

Pentru versiunile anterioare, ar trebui să mutați codul clasei într-un modul separat și Instancesă înlocuiți declarația cu o declarație a unei variabile globale în secțiunea sa (nu existau secțiuni implementationînainte de Delphi 7 inclusiv ). class varstrict private

Dart

Exemplu de dart

Bazat pe constructorul fabricii din documentația Dart

class Singleton { static final Singleton _singleton = Singleton . _intern (); fabrică Singleton () { return _singleton ; } singleton . _intern (); }

Io

Io exemplu Singleton := Clona obiect Singleton clone := Singleton

Ruby

Exemplu în Ruby clasa Singleton def self . noua @instanță ||= sfârșit super final

Biblioteca standard (Ruby 1.8 și mai sus) include modulul Singleton, care face crearea singleton-urilor și mai ușoară:

necesită clasa „singleton” Foo include Singleton end a = Foo . instanța # Foo.new nu este disponibilă, pentru a obține o referință la o (unică) # instanță a clasei Foo, utilizați metoda Foo#instance

Common Lisp

Exemplu în Common Lisp ( defclass singleton-class () ;; metaclasă care implementează mecanismul singleton (( instance :initform nil ))) ( defmethod validate-superclass (( clasa singleton-class ) ( superclasa standard-class )) t ) ;; Permite claselor singleton să moștenească din clasele normale ( defmethod validate-superclass (( clasa singleton-class ) ( superclasa singleton-class )) t ) ;;Permite claselor singleton să moștenească de la alte clase singleton ( defmethod validate-superclass (( clasa standard-clasa ) ( superclasa singleton-class )) nil ) ;;Interziceți moștenirea claselor obișnuite de la singletons ( defmethod make-instance (( clasa singleton-class ) &key ) ( cu sloturi ( instanță ) clasă ( sau instanță ( instanță setf ( call-next-method ))))) ( defclass my-singleton-class () () ( :metaclass singleton-class ))

VB.NET

Exemplu în VB.NET Programul Modulului Sub Main () Dim T1 As Singleton = Singleton . getInstance T1 . valoare = 1000 Dim T2 As Singleton = Singleton . Consola getInstance . WriteLine ( T2 . Value ) Consola . Citiți () End Sub Încheiați modulul Singleton de clasă publică Valoarea publică ca număr întreg „Nu permiteți constructorul Protected Sub New () End Sub Private NotInheritable Class SingletonCreator Private Shared Only ReadOnly m_instance As New Singleton () Instanță de proprietate publică partajată numai ReadOnly () As Singleton Get Return m_instance End Get End Property End Class Proprietate publică partajată numai pentru citire getInstance () As Singleton Get Return SingletonCreator . Instance End Obține proprietatea End termina clasa

Perl

Exemplu Perl utilizați v5.10 ; _ folosiți strict ; pachet Singleton ; sub new { # Declararea unei variabile statice $instance # și returnarea acesteia ca rezultat al executării metodei new state $instance = bless {}; } pachet principal ; my $a = Singleton -> nou ; my $b = Singleton -> nou ; spune "$a $b" ; # Referințele $a și $b indică același obiect

Perl

Exemplu Perl cu obiect imuabil #!/usr/bin/perl -w utilizați caracteristica „spune” ; folosiți strict ; folosiți avertismente ; pachet Singleton { $instanţa mea ; # instanță de clasă (câmp static) # -- ** constructor ** -- sub new { my $class = shift ; exceptând cazul în care ( $instanță ) { # verificați dacă există deja o instanță a clasei $instanță = { # dacă nu, creați una nouă și scrieți numele persoanei pentru a o saluta name => shift , }; binecuvântează $instanţă , $clasă ; } return $instanta ; # returnează singura instanță a clasei noastre } # -- ** salut ** -- sub hello { my ( $self ) = ( shift ); spune „Bună ziua, $self->{name}” ; # să salutăm proprietarul acestui obiect } } my $a = Singleton -> new ( 'Alex' ); # creați o instanță a unei clase numită Alex my $b = Singleton -> new ( 'Barney' ); # ... acum încerc să creez o altă instanță pentru Barney $a -> salut (); # Salut, Alex # da, salut Alex $b -> salut (); # Bună, Alex # hopa, Barney, îmi pare rău, ce neînțelegere...

ActionScript 3

Exemplu ActionScript

Opțiune de clasă privată:

pachet { public class Singleton { private static var _instance : Singleton ; funcție publică Singleton ( privateClass : PrivateClass ) { } funcția publică statică getInstance () : Singleton { if ( ! _instance ) _instance = new Singleton ( new PrivateClass ()); return _instanță ; } } } // Deoarece clasa este declarată în același fișier în afara // pachetului, numai clasa Singleton o poate folosi. class PrivateClass { public function PrivateClass () { } }

Aruncarea unei opțiuni de excepție:

pachet { public class Singleton { public static const instanță : Singleton = new Singleton (); public function Singleton () { // Boolean(Singleton) este fals dacă clasa // este instanțiată înainte ca constructorul static să fie executat dacă ( Singleton ) throw new Error ( "Clasa este singleton." ); } } }

Opțiune cu variabilă de acces:

pachet { clasă publică MySingleton { private static var _instance : MySingleton ; // Acces variabila private static var _isConstructing : Boolean ; public function MySingleton () { if ( ! _isConstructing ) throw new Error ( "Singleton, use MySingleton.instance" ); } funcția publică statică get instance () : MySingleton { if ( _instance == null ) { _isConstructing = true ; _instance = new MySingleton (); _isConstructing = false ; } return _instanță ; } } }

Avantajele opțiunii de clasă privată:

  • Dacă încercați să utilizați direct constructorul, compilatorul va detecta eroarea imediat. // Nu este singurul beneficiu al acestei metode
  • Obiectul este creat la cerere.

Dezavantajul opțiunii de clasă privată:

  • Puteți înlocui clasa privată cu a dvs. cu același nume.

Avantajele opțiunii de excepție:

  • Mai puțin cod.

CoffeeScript

Exemplu în CoffeeScript

Abordare clasică (Coffeescript ≠ 1,5)

clasa Singleton instanță = constructor nedefinit : -> if instance ? returnează instanță else instance = @ # Cod constructor consola . assert ( noul Singleton este nou Singleton );

Abordare bazată pe capacitatea de a accesa o funcție din corpul acesteia (Coffeescript ≠ 1,5)

class Singleton init = -> # constructor ca metodă de clasă privată # Cod constructor # ... # Înlocuiți constructorul, păstrând acest (@) init = => @ return @ # Constructor real. Servește pentru a apela init # return trebuie folosit, altfel va returna acest constructor (@) : -> return init . aplica ( @ , argumente ) consola . assert ( noul Singleton este nou Singleton ) Notă: schimbarea constructorului real de la sine, i.e. constructor: -> Singleton = => @ nu va da nimic, pentru că în codul JavaScript rezultat, constructorul indică constructorul local Singleton, nu clasa Singleton.

Cu toate acestea, dacă utilizați spații de nume, atunci această opțiune este posibilă:

ns = {} clasa ns . Singleton constructor : -> # Cod constructor ns.Singleton == > @ consola . assert ( new ns . Singleton este nou ns . Singleton )

JavaScript

Exemplu JavaScript cu încapsulare

O metodă bazată pe ascunderea variabilelor folosind închideri. Ca bonus - capacitatea de a declara metode și proprietăți private care vor fi disponibile atât pentru constructor, cât și pentru metodele „clasă”.

const Singleton = ( function () { let instance ; // Metode și proprietăți private // Funcția de constructor Singleton () { if ( instance ) return instance ; instanță = aceasta ; } // Metode publice Singleton . prototip . test = funcția () {}; întoarcere Singleton ; })(); consola . jurnal ( new Singleton () === new Singleton ());

Fără a folosi ascunderea variabilelor, există o soluție simplă bazată pe faptul că funcția Singleton este un obiect. Dezavantajul este capacitatea de a schimba proprietatea instanței în afara clasei:

function Singleton () { const instance = Singleton . instanță ; if ( instanță ) returnează instanță ; singleton . instanță = aceasta ; } singleton . prototip . test = function () {}; consola . jurnal ( new Singleton () === new Singleton ());

Cea mai scurtă variantă.

const Singleton = new ( function () { const instance = this ; return function () { return instance ; }; })(); consola . jurnal ( new Singleton () === new Singleton ());

Folosind câmpuri private statice ale unei clase JS:

clasa Singleton { static # onlyInstance = null ; constructor (){ if ( ! Singleton . # onlyInstance ){ Singleton . # onlyInstance = this ; } else { return Singleton . # onlyInstance ; } } } consola . jurnal ( new Singleton () === new Singleton ());

Obiectiv-C

Exemplu în Obiectivul-C

singleton.h

@interfață Singleton  : NSObject { } + ( Singleton * ) sharedInstance ; @Sfârşit

singleton.m

@implementationSingleton _ static Singleton * _sharedInstance = nil ; + ( Singleton * ) sharedInstance { @sincronizat ( sine ) { dacă ( ! _sharedInstance ) { _sharedInstance = [[ Singleton alloc ] init ]; } } returnează _sharedInstance ; } @Sfârşit

Sau (doar pentru OS X 10.6+, iOS 4.0+):

@implementationSingleton _ + ( Singleton * ) sharedInstance { static dispatch_once_t pred ; static Singleton * sharedInstance = nil ; dispatch_once ( & pred , ^ { sharedInstance = [[ self alloc ] init ]; }); returnează sharedInstance ; } @Sfârşit

Swift

Exemplu rapid clasa Singleton { static let shared = Singleton () private init () { } }

Scala, Kotlin

Exemplu în Scala și Kotlin obiect Singleton {} // cuvântul cheie „obiect” creează o clasă care implementează modelul „singleton” în mod implicit

Vezi și

Literatură

  • Alan Shalloway, James R. Trott Design Patterns. O nouă abordare a designului orientat pe obiecte = Modelele de design explicate: O nouă perspectivă asupra designului orientat pe obiecte. - M .: „Williams”, 2002. - S. 288. - ISBN 0-201-71594-5 .
  • Eric Freeman, Elizabeth Freeman. Modele de design = Head First Design Patterns. - Sankt Petersburg. : Peter, 2011. - 656 p. - ISBN 978-5-459-00435-9 .

Link -uri

Note