Samotář (designový vzor)

Aktuální verze stránky ještě nebyla zkontrolována zkušenými přispěvateli a může se výrazně lišit od verze recenzované 15. listopadu 2020; ověření vyžaduje 101 úprav .
samotář
jedináček
Typ generování
profesionálové organizuje API; implicitně načte správné moduly ve správném pořadí; ponechává prostor pro druhý podobný objekt
Mínusy komplikuje testování, multithreading a sledování latence; singletony by na sobě neměly implicitně záviset
Popsáno v Návrhové vzory Ano

Singleton je generativní návrhový vzor ,  ​​který zaručuje, že v aplikaci s jedním vláknem bude existovat jediná instance určité třídy, a poskytuje k této instanci globální přístupový bod.

Účel

Třída pouze jednu instanci a poskytuje k ní globální přístupový bod. Když se pokusíte vytvořit tento objekt , vytvoří se pouze v případě, že ještě neexistuje, jinak se vrátí odkaz na již existující instanci a nedojde k žádné nové alokaci paměti. Je nezbytné, aby bylo možné použít instanci třídy, protože v mnoha případech je k dispozici širší funkčnost. Například k popsaným komponentám třídy lze přistupovat prostřednictvím rozhraní , pokud je taková možnost podporována jazykem.

Někdy je potřeba globální „osamělý“ objekt – jmenovitě objekt ( ), a nikoli sada procedur, které nejsou spojeny s žádným objektem ( ): log().put("Test");logPut("Test");

Takové objekty lze také vytvořit během inicializace programu. To může vést k následujícím potížím:

Pro

Nevýhody

Aplikace

Příklady použití

Příklady implementace

Java 1.6

Příklad Java 1.6: žádné vnitřní třídy (líná nesynchronizovaná implementace) public class Singleton { private static Singleton instance ; private Singleton () {}; public static Singleton getInstance () { if ( instance == null ) { instance = new Singleton (); } návrat instance ; } }

Java

Příklad Java: Synchronized Accessor

Tato možnost blokuje metodu getInstance() bez ohledu na to, zda jsme vytvořili jednu instanci nebo ne. To zpomaluje program, pokud potřebujete často získat objekt Singleton z různých vláken.

public class Singleton { private static Singleton instance ; private Singleton () {}; public static synchronized Singleton getInstance () { if ( instance == null ) { instance = new Singleton (); } návrat instance ; } }

Java

Příklad Java: žádná líná inicializace, použití statického inicializátoru public class Singleton { private static Singleton instance ; static { instance = new Singleton (); // Zpracování výjimek je možné v tomto bloku } soukromý Singleton () {} public static Singleton getInstance () { return instance ; } }

Java 1.5

Příklad Java 1.5: Inicializace on Demand Holder public class Singleton { private Singleton () {} private static class SingletonHolder { public static final Singleton instance = new Singleton (); } public static Singleton getInstance () { return SingletonHolder . instance ; } }

Java 1.5

Příklad Java 1.5: Enum singleton public enum SingletonEnum { INSTANCE ; public void someMetoda () { *** } public void otherMetoda () { *** } }

Python

Od PEP 0318 Archivováno 3. června 2020 na Wayback Machine :

Příklad Pythonu s dekorátory def singleton ( cls ): instance = {} def getinstance (): pokud cls není v instancích : instance [ cls ] = cls () return instance [ cls ] return getinstance @singleton class MyClass : ...

Python

Od PEP 0318 Archivováno 3. června 2020 na Wayback Machine :

Příklad Pythonu na MetaClasses třída MetaSingleton ( typ ): _instances = {} def __call__ ( cls , * args , ** kwargs ): pokud cls není v cls . _instance : cls . _instance [ cls ] = super ( MetaSingleton , cls ) . __call__ ( * args , ** kwargs ) return cls . _instance [ cls ] třída MyClass ( metaclass = MetaSingleton ): ...

C++

Následuje jedna z možných implementací vzoru Singleton v C++ (známý jako Myers singleton ), kde singleton je statický lokální objekt. Důležité je, že konstruktor třídy je deklarován jako private, což zabraňuje instanci třídy mimo její implementaci. Kromě toho jsou konstruktor kopírování a operátor přiřazení také deklarovány jako soukromé. Ty by měly být deklarovány, ale ne definovány, protože to umožňuje snadno zjistitelnou chybu propojení, pokud jsou náhodně volány z kódu. Všimněte si také, že výše uvedený příklad není bezpečný pro vlákna v C++03, abyste mohli pracovat s třídou z více vláken, musíte proměnnou chránit theSingleInstancepřed souběžným přístupem, například pomocí mutexu nebo kritické sekce . Nicméně v C++11 je Myers singleton bezpečný pro vlákna a bez zámku.

Příklad v C++ třída OnlyOne { veřejnost : statický OnlyOne & Instance () { static OnlyOne theSingleInstance ; return theSingleInstance ; } soukromé : OnlyOne (){} OnlyOne ( const OnlyOne & root ) = delete ; OnlyOne & operator = ( const OnlyOne & ) = delete ; };

Další příklad implementace singletonu v C++ s možností dědění pro vytvoření rozhraní, jehož framework bude ve skutečnosti singleton. Životnost jednoho předmětu je pohodlně řízena pomocí mechanismu počítání referencí .

Příklad v C++ třídy Singleton { chráněno : statický Singleton * _self ; Singleton () {} virtuální ~ Singleton () {} veřejnost : statický Singleton * Instance () { pokud ( ! _self ) { _self = new Singleton (); } return _self ; } statický bool DeleteInstance () { jestliže ( _self ) { smazat_sebe ; _ _self = 0 ; vrátit true ; } vrátit false ; } }; Singleton * Singleton :: _self = 0 ;

C#

Příklad v C#

Nejjednodušší způsob, jak implementovat vláknově bezpečný a líný singleton, však vyžaduje .NET verze 4 nebo vyšší.

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

Pro línou inicializaci Singletonu v C# se doporučuje použít typové konstruktory (statický konstruktor). CLR automaticky vyvolá konstruktor typu při prvním přístupu k typu, přičemž zachovává bezpečnost synchronizace vláken. Typový konstruktor je automaticky vygenerován překladačem a v něm jsou inicializována všechna pole typu (statická pole). Neměli byste explicitně nastavovat konstruktor typu, protože v tomto případě bude zavolán bezprostředně před voláním typu a kompilátor JIT nebude schopen použít optimalizaci (například pokud k prvnímu volání Singleton dojde ve smyčce) .

/// generic Singleton<T> (bezpečné pro vlákna pomocí generické třídy a líné inicializace) /// <typeparam name="T">Třída Singleton</typeparam> public class Singleton < T > kde T : class { /// Chráněný konstruktor je potřeba, aby se zabránilo vytvoření instance třídy Singleton. /// Bude volána ze soukromého konstruktoru zděděné třídy. chráněný Singleton () { } /// Továrna se používá k líné inicializaci instance třídy private sealed class SingletonCreator < S > kde S : class { //Použito Reflection k vytvoření instance třídy bez veřejného konstruktoru private static pouze pro čtení S instance = ( S ) typeof ( S ). GetConstructor ( BindingFlags . Instance | BindingFlags . NonPublic , null , nový typ [ 0 ], nový ParametrModifier [ 0 ]). Invoke ( null ); public static S CreatorInstance { get { return instance ; } } } public static T Instance { get { return SingletonCreator < T >. CreatorInstance ; } } } /// Použití veřejné třídy Singleton TestClass : Singleton < TestClass > { /// Volá chráněný konstruktor třídy Singleton private TestClass () { } public string TestProc () { return "Ahoj světe" ; } }

Můžete také použít standardní implementaci Singleton zabezpečenou pomocí líné inicializace:

public class Singleton { /// Chráněný konstruktor je potřeba k zabránění vytvoření instance třídy Singleton protected Singleton () { } private sealed class SingletonCreator { private static pouze pro čtení Singleton instance = new Singleton (); public static Singleton Instance { get { return instance ; } } } public static Singleton Instance { get { return SingletonCreator . instance ; } } }

Pokud nejsou potřeba žádné veřejné statické metody nebo vlastnosti (jiné než vlastnost Instance), lze použít zjednodušenou verzi:

public class Singleton { private static pouze pro čtení Singleton instance = new Singleton (); public static Singleton Instance { get { return instance ; } } /// Chráněný konstruktor je potřeba, aby se zabránilo vytvoření instance třídy Singleton chráněné Singleton () { } }

Příklad líné inicializace

jmenný prostor Singleton { public class Singleton { private static Singleton instance ; public static Singleton Instance { get { return instance ?? ( instance = nový Singleton ()); } } chráněný Singleton () { } } }

PHP 4

Příklad v PHP4 <?php class Singleton { function Singleton ( $directCall = true ) { if ( $directCall ) { trigger_error ( "Nelze použít konstruktor k vytvoření třídy Singleton. Použijte statickou metodu getInstance()" , E_USER_ERROR ); } //TODO: Zde přidejte kód hlavního konstruktoru } function & getInstance () { static $instance ; if ( ! is_object ( $instance ) ) { $class = __CLASS__ ; $instance = new $class ( false ); } return $instance ; } } //použití $test = & Singleton :: getInstance (); ?>

PHP 5

Příklad v PHP5 <?php class Singleton { private static $instance ; // soukromá funkce instance objektu __construct (){ /* ... @return Singleton */ } // Ochrana před vytvořením pomocí nové soukromé funkce Singleton __clone () { /* ... @return Singleton */ } // Ochrana před vytvoření pomocí klonování privátní funkce __wakeup () { /* ... @return Singleton */ } // Ochrana před vytvořením pomocí zrušení serializace veřejné statické funkce getInstance () { // Vrátí jednu instanci třídy. @return Singleton if ( empty ( self :: $instance ) ) { self :: $instance = new self (); } return self :: $instance ; } public function doAction () { } } /* Aplikace */ Singleton :: getInstance () -> doAction (); // ?>

PHP 5.4

Příklad v PHP5.4 <?php vlastnost Singleton { private static $instance = null ; private function __construct () { /* ... @return Singleton */ } // Ochrana před vytvořením pomocí nové soukromé funkce Singleton __clone () { /* ... @return Singleton */ } // Ochrana před vytvořením pomocí klonu private function __wakeup () { /* ... @return Singleton */ } // Chránit před vytvořením pomocí unserialize public static function getInstance () { return self :: $instance === null ? self :: $instance = new static () // Pokud je $instance 'null', pak vytvořte objekt new self() : self :: $instance ; // Else vrátí existující objekt } } /** * Class Foo * @method static Foo getInstance() */ class Foo { use Singleton ; private $bar = 0 ; public function incBar () { $this -> bar ++ ; } public function getBar () { return $this -> bar ; } } /* Aplikace */ $foo = foo :: getInstance (); $foo -> incBar (); var_dump ( $foo -> getBar ()); $foo = foo :: getInstance (); $foo -> incBar (); var_dump ( $foo -> getBar ()); ?>

Delphi

Pro Delphi 2005 a vyšší je vhodný následující příklad (není bezpečný pro vlákna):

Příklad Delphi typ TSingleton = class strict private class var Instance : TSingleton ; public class function NewInstance : TObject ; přepsat ; konec ; funkce třídy TSingleton . NewInstance : TObject ; begin if not Assigned ( Instance ) then Instance := TSingleton ( zděděná NewInstance ) ; Vysledek := Instance ; konec ;

U dřívějších verzí byste měli přesunout kód třídy do samostatného modulu a Instancenahradit deklaraci deklarací globální proměnné v její sekci ( implementationpřed Delphi 7 včetně class varnebyly žádné sekce strict private).

Dart

Příklad šipky

Na základě továrního konstruktéra z dokumentace Dart

class Singleton { static final Singleton _singleton = Singleton . _interní (); továrna Singleton () { return _singleton ; } singleton . _interní (); }

Io

Příklad Io Singleton := Objektový klon Singletonový klon := Singleton

Ruby

Příklad v Ruby třída Singleton def self . new @instance ||= super end end

Standardní knihovna (Ruby 1.8 a vyšší) obsahuje modul Singleton, díky kterému je vytváření singletonů ještě jednodušší:

vyžadovat třídu 'singleton' Foo include Singleton end a = Foo . instance # Foo.new není k dispozici, k získání odkazu na (jedinou) # instanci třídy Foo použijte metodu Foo#instance

Common Lisp

Příklad v Common Lisp ( defclass singleton-class () ;; metatřída, která implementuje mechanismus singleton (( instance :initform nil ))) ( defmethod validate- superclass (( class singleton-class ) ( superclass standard-class )) t ) ;;Umožnit singletonovým třídám dědit z normálních tříd ( defmethod validate- superclass (( class singleton-class ) ( superclass singleton-class )) t ) ;;Umožnit singletonovým třídám dědit z jiných singletonových tříd ( defmethod validate- superclass (( class standard-class ) ( superclass singleton-class )) nil ) ;;Zakázat běžným třídám dědit z singletonů ( defmethod make-instance (( class singleton-class ) &key ) ( with-slots ( instance ) class ( nebo instance ( setf instance ( call-next-method ))))) ( defclass my-singleton-class () () ( :metaclass singleton-class ))

VB.NET

Příklad ve VB.NET Modulový program Sub Main () Dim T1 As Singleton = Singleton . getInstance T1 . hodnota = 1000 Dim T2 As Singleton = Singleton . konzole getInstance . WriteLine ( T2 . Value ) Konzole . Přečíst () End Sub Koncový modul Veřejná třída Singleton Veřejná hodnota jako celé číslo 'Nepovolit konstruktor Protected Sub New () End Sub Private NotInheritable Class SingletonCreator Private Shared Only ReadOnly m_instance As New Singleton () Veřejná sdílená instance vlastnosti pouze pro čtení () As Singleton Get Return m_instance End Get End End Property End Class Veřejná sdílená vlastnost pouze pro čtení getInstance ( ) As Singleton Get Return SingletonCreator . Instance End Get End Property závěrečná třída

Perl

Příklad Perlu použít v5.10 ; _ používat přísný ; balení Singleton ; sub new { # Deklarace statické proměnné $instance # a její vrácení jako výsledek provedení metody new state $instance = bless {}; } hlavní balíček ; my $a = Singleton -> new ; my $b = Singleton -> new ; řekněte "$a $b" ; # Odkazy $a a $b ukazují na stejný objekt

Perl

Příklad Perlu s neměnným objektem #!/usr/bin/perl -w použijte funkci "řekni" ; používat přísný ; používat varování ; balíček Singleton { moje $instance ; # instance třídy (statické pole) # -- ** konstruktor ** -- sub new { my $ class = shift ; if ( $instance ) { # zkontrolujte, zda již existuje instance třídy $instance = { # pokud ne, vytvořte novou a napište jméno osoby, kterou chcete pozdravit name => shift , }; požehnej $instance , $třída ; } return $instance ; # vrátit jedinou instanci naší třídy } # -- ** ahoj ** -- sub ahoj { my ( $self ) = ( shift ); řekni "Ahoj, $self->{name}" ; # pojďme pozdravit vlastníka tohoto objektu } } my $a = Singleton -> new ( 'Alex' ); # vytvořte instanci třídy s názvem Alex my $b = Singleton -> new ( 'Barney' ); # ... nyní se pokouším vytvořit další instanci pro Barney $a -> hello (); # Ahoj, Alexi # ano, ahoj Alex $b -> ahoj (); # Ahoj, Alexi # Jejda, Barney, promiň, jaké nedorozumění...

ActionScript 3

Příklad jazyka ActionScript

Možnost soukromé třídy:

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 ()); return _instance ; } } } // Protože je třída deklarována ve stejném souboru mimo // balíček, může ji používat pouze třída Singleton. class PrivateClass { public function PrivateClass () { } }

Vyvolání možnosti výjimky:

package { public class Singleton { public static const instance : Singleton = new Singleton (); public function Singleton () { // Boolean(Singleton) má hodnotu false, pokud je třída // vytvořena před provedením statického konstruktoru if ( Singleton ) throw new Error ( "Třída je singleton." ); } } }

Možnost s přístupovou proměnnou:

balíček { public class MySingleton { private static var _instance : MySingleton ; // Přístup k proměnné private static var _isConstructing : Boolean ; public function MySingleton () { if ( ! _isConstructing ) throw new Error ( "Singleton, použijte MySingleton.instance" ); } public static function get instance () : MySingleton { if ( _instance == null ) { _isConstructing = true ; _instance = new MySingleton (); _isConstructing = false ; } return _instance ; } } }

Výhody možnosti soukromé třídy:

  • Pokud se pokusíte použít konstruktor přímo, kompilátor chybu okamžitě zachytí. // Není to jediná výhoda této metody
  • Objekt je vytvořen na vyžádání.

Nevýhoda možnosti soukromé třídy:

  • Soukromou třídu můžete nahradit svou vlastní se stejným názvem.

Výhody možnosti výjimky:

  • Méně kódu.

CoffeeScript

Příklad v CoffeeScript

Klasický přístup (Coffeescript ≠ 1,5)

instance třídy Singleton = nedefinovaný konstruktor : -> if instance ? vrátit instanci else instance = @ # Kód konstruktoru konzole . tvrdit ( nový Singleton je nový Singleton );

Přístup založený na možnosti přístupu k funkci z jejího těla (Coffeescript ≠ 1.5)

class Singleton init = -> # konstruktor jako metoda soukromé třídy # Kód konstruktoru # ... # Nahraďte konstruktor a ponechte tento (@) init = => @ return @ # Skutečný konstruktér. Slouží k volání init # return musí být použit, jinak vrátí tento konstruktor (@): -> return init . použít ( @ , argumenty ) konzole . tvrdit ( nový Singleton je nový Singleton ) Poznámka: změna skutečného konstruktoru od sebe sama, tzn. konstruktor: -> Singleton = => @ nedá nic, protože ve výsledném kódu JavaScript konstruktor ukazuje na místní konstruktor Singleton, nikoli na třídu Singleton.

Pokud však používáte jmenné prostory, pak je tato možnost možná:

ns = {} třída ns . Singleton konstruktor: -> # Kód konstruktoru ns.Singleton == > @ konzole . potvrdit ( nové ns . Singleton je nové ns . Singleton )

JavaScript

Příklad JavaScriptu se zapouzdřením

Metoda založená na skrývání proměnných pomocí uzávěrů. Jako bonus - možnost deklarovat soukromé metody a vlastnosti, které budou dostupné jak konstruktoru, tak metodám "třídy".

const Singleton = ( function () { let instance ; // Soukromé metody a vlastnosti // Funkce konstruktoru Singleton () { if ( instance ) return instance ; instance = tento ; } // Public Methods Singleton . prototyp . test = funkce () {}; návrat Singleton ; })(); konzole . log ( new Singleton () === new Singleton ());

Bez použití skrývání proměnných existuje jednoduché řešení založené na tom, že funkce Singleton je objekt. Nevýhodou je možnost změnit vlastnost instance mimo třídu:

function Singleton () { const instance = Singleton . instance ; if ( instance ) return instance ; singleton . instance = tento ; } singleton . prototyp . test = funkce () {}; konzole . log ( new Singleton () === new Singleton ());

Nejkratší varianta.

const Singleton = new ( function () { const instance = this ; return function () { return instance ; }; })(); konzole . log ( new Singleton () === new Singleton ());

Použití statických soukromých polí třídy JS:

class Singleton { static # onlyInstance = null ; konstruktor (){ if ( ! Singleton . # onlyInstance ){ Singleton . # onlyInstance = this ; } else { return Singleton . # onlyInstance ; } } } konzole . log ( new Singleton () === new Singleton ());

Objective-C

Příklad v Objective-C

singleton.h

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

singleton.m

@implementationSingleton _ static Singleton * _sharedInstance = nil ; + ( Singleton * ) sharedInstance { @synchronized ( self ) { if ( ! _sharedInstance ) { _sharedInstance = [[ Singleton alloc ] init ]; } } return _sharedInstance ; } @konec

Nebo (pouze pro OS X 10.6+, iOS 4.0+):

@implementationSingleton _ + ( Singleton * ) sharedInstance { static dispatch_once_t pred ; static Singleton * sharedInstance = nula ; dispatch_once ( & pred , ^ { sharedInstance = [[ self alloc ] init ]; }); return sharedInstance ; } @konec

Swift

Rychlý příklad class Singleton { static let shared = Singleton () private init () { } }

Scala, Kotlin

Příklad v Scala a Kotlin object Singleton {} // klíčové slovo "object" vytvoří třídu, která standardně implementuje vzor "singleton".

Viz také

Literatura

  • Alan Shalloway, James R. Trott Návrhové vzory. Nový přístup k objektově orientovanému navrhování = vysvětlení návrhových vzorů: Nový pohled na objektově orientovaný design. - M.: "Williams", 2002. - S. 288. - ISBN 0-201-71594-5 .
  • Eric Freeman, Elizabeth Freeman. Design Patterns = Návrhové vzory Head First. - Petrohrad. : Peter, 2011. - 656 s. - ISBN 978-5-459-00435-9 .

Odkazy

Poznámky