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ță.
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:
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ță ; } }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 : ...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 ): ...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 ;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 () { } } }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
Bazat pe constructorul fabricii din documentația Dart
class Singleton { static final Singleton _singleton = Singleton . _intern (); fabrică Singleton () { return _singleton ; } singleton . _intern (); }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#instanceOpț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ă:
Dezavantajul opțiunii de clasă privată:
Avantajele opțiunii de excepție:
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 )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 ());singleton.h
@interfață Singleton : NSObject { } + ( Singleton * ) sharedInstance ; @Sfârşitsingleton.m
@implementationSingleton _ static Singleton * _sharedInstance = nil ; + ( Singleton * ) sharedInstance { @sincronizat ( sine ) { dacă ( ! _sharedInstance ) { _sharedInstance = [[ Singleton alloc ] init ]; } } returnează _sharedInstance ; } @SfârşitSau (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şitModele de design | |
---|---|
Principal | |
Generativ | |
Structural | |
Comportamental | |
Programare în paralel |
|
arhitectural |
|
Șabloane Java EE | |
Alte șabloane | |
Cărți | |
Personalități |