Loner (tervezési minta)

Az oldal jelenlegi verzióját még nem ellenőrizték tapasztalt közreműködők, és jelentősen eltérhet a 2020. november 15-én felülvizsgált verziótól ; az ellenőrzéshez 101 szerkesztés szükséges .
magányos
Szingli
Típusú generáló
profik megszervezi az API-t; implicit módon betölti a megfelelő modulokat a megfelelő sorrendben; helyet hagy egy második hasonló tárgynak
Mínuszok bonyolítja a tesztelést, a többszálú kezelést és a késleltetés követését; a singletonok nem függhetnek implicit módon egymástól
Leírása: Tervezési minták Igen

A  singleton egy generatív tervezési minta , amely garantálja, hogy egy bizonyos osztály egyetlen példánya lesz egy egyszálú alkalmazásban, és globális hozzáférési pontot biztosít ehhez a példányhoz.

Cél

Az osztálynak csak egy példánya van, és globális hozzáférési pontot biztosít hozzá. Amikor megpróbálja létrehozni ezt az objektumot , csak akkor jön létre, ha még nem létezik, ellenkező esetben a rendszer egy már létező példányra hivatkozik, és nem történik új memóriafoglalás. Lényeges, hogy az osztály egy példányát lehessen használni , mivel sok esetben szélesebb körű funkcionalitás válik elérhetővé. Például a leírt osztályösszetevők a felületen keresztül érhetők el , ha ezt a lehetőséget a nyelv támogatja.

Néha szükség van egy globális "magányos" objektumra - nevezetesen egy objektumra ( ), és nem egy objektumhoz ( ) nem társított eljárások halmazára :log().put("Test");logPut("Test");

Ilyen objektumok a program inicializálása során is létrehozhatók. Ez a következő nehézségekhez vezethet:

Előnyök

Hátrányok

Alkalmazás

Használati példák

Megvalósítási példák

Java 1.6

Java 1.6 példa: nincsenek belső osztályok (lusta, nem szinkronizált megvalósítás) public class Singleton { private static Singleton példány ; privát Singleton () {}; public static Singleton getInstance () { if ( példány == null ) { példány = new Singleton (); } return instance ; } }

Java

Java példa: Synchronized Accessor

Ez az opció blokkolja a getInstance() metódust, akár egyetlen példányt hoztunk létre, akár nem. Ez lelassítja a programot, ha gyakran kell Singleton objektumot beszereznie különböző szálakból.

public class Singleton { private static Singleton példány ; privát Singleton () {}; public static synchronized Singleton getInstance () { if ( példány == null ) { példány = new Singleton (); } return instance ; } }

Java

Java példa: nincs lusta inicializálás, statikus inicializátor használata public class Singleton { private static Singleton példány ; static { példány = new Singleton (); // Kivételkezelés lehetséges ebben a blokkban } privát Singleton () {} public static Singleton getInstance () { return példány ; } }

Java 1.5

Java 1.5 példa: Inicializálás igény szerint public class Singleton { private Singleton () {} private static class SingletonHolder { public static final Singleton példány = new Singleton (); } public static Singleton getInstance () { return SingletonHolder . példány ; } }

Java 1.5

Java 1.5 példa: Enum singleton public enum SingletonEnum { INSTANCE ; public void someMethod () { *** } public void otherMethod () { *** } }

Python

A PEP 0318 dokumentumból archiválva 2020. június 3-án a Wayback Machine -nél :

Python példa dekorátorokkal def singleton ( cls ): példányok = {} def getinstance (): ha a cls nincs példányokban : példányok [ cls ] = cls () return példányok [ cls ] return getinstance @singleton class MyClass : ...

Python

A PEP 0318 dokumentumból archiválva : 2020. június 3. a Wayback Machine -nél :

Python példa a MetaClasses-on osztály MetaSingleton ( típus ): _instances = {} def __call__ ( cls , * args , ** kwargs ): ha a cls nincs a cls -ben . _instances : cls . _instances [ cls ] = szuper ( MetaSingleton , cls ) . __call__ ( * args , ** kwargs ) return cls . _instances [ cls ] osztály MyClass ( metaclass = MetaSingleton ): ...

C++

Az alábbiakban a Singleton minta egyik lehetséges megvalósítása a C++ nyelvben ( Myers szinglitonként ismert ), ahol a szingleton egy statikus lokális objektum. A lényeg az, hogy az osztálykonstruktort ként deklarálják private, ami megakadályozza az osztály példányosítását a megvalósításán kívül. Ezen túlmenően a másolatkészítő és a hozzárendelés operátora is magánszemélynek van nyilvánítva. Ez utóbbit deklarálni kell, de nem definiálni, mivel ez könnyen észlelhető linkelési hibát tesz lehetővé, ha véletlenül kódból hívják meg őket. Vegye figyelembe azt is, hogy a fenti példa nem szálbiztos C++03-ban, ha több szálból álló osztállyal szeretne dolgozni, meg kell védenie a változót theSingleInstancea párhuzamos hozzáféréstől, például mutex vagy kritikus szakasz használatával . A C++11 -ben azonban a Myers singleton szálbiztos és zármentes.

Példa C++ nyelven osztály OnlyOne { nyilvános : statikus OnlyOne & Instance () { statikus OnlyOne theSingleInstance ; return theSingleInstance ; } privát : OnlyOne (){} OnlyOne ( const OnlyOne & root ) = törlés ; OnlyOne & operator = ( const OnlyOne & ) = törlés ; };

Egy másik példa egy szingli C ++-ban való megvalósítására, öröklési lehetőséggel egy interfész létrehozására, amelynek kerete valójában egy szingli lesz. Egyetlen objektum élettartama kényelmesen szabályozható a referenciaszámláló mechanizmussal .

Példa C++ nyelven osztályú Singleton { védett : statikus Singleton * _self ; Singleton () {} virtuális ~ Singleton () {} nyilvános : statikus Singleton * Példány () { ha ( ! _self ) { _self = új Singleton (); } return _self ; } statikus bool DeleteInstance () { ha ( _self ) { delete_self ; _ _self = 0 ; return true ; } return false ; } }; Singleton * Singleton :: _self = 0 ;

C#

Példa a C# -ban

A szálbiztos és lusta singleton megvalósításának legegyszerűbb módja azonban a .NET 4-es vagy újabb verzióját igényli.

public pecsétes osztály Singleton { private static readonly Lazy < Singleton > instanceHolder = new Lazy < Singleton >(() => new Singleton ()); privát Singleton () { ... } public static Singleton Instance { get { return instanceHolder . érték ; } } }

A Singleton C#-ban való lusta inicializálásához típuskonstruktorok (statikus konstruktor) használata javasolt. A CLR automatikusan meghívja a típus konstruktorát a típus első elérésekor, miközben megőrzi a szálszinkronizálás biztonságát. A típuskonstruktort a fordító automatikusan generálja, és a típus összes mezője (statikus mező) inicializálódik benne. A típuskonstruktort nem szabad kifejezetten beállítani, mert ebben az esetben az közvetlenül a típus meghívása előtt kerül meghívásra, és a JIT fordító nem tudja alkalmazni az optimalizálást (például ha a Singleton első hívása ciklusban történik) .

/// általános Singleton<T> (a szál biztonságos általános osztályt és lusta inicializálást használ) /// <typeparam name="T">Singleton osztály</typeparam> public class Singleton < T > ahol T : class { /// A védett konstruktorra azért van szükség, hogy megakadályozzuk a Singleton osztály példányosítását. /// Az örökölt osztály privát konstruktora hívja meg. védett Singleton () { } /// Egy gyár egy osztálypéldány lusta inicializálására szolgál, privát lezárt class SingletonCreator < S > ahol S : class { //Reflection használja egy nyilvános konstruktor nélküli osztály példányosítására private static only S instance = ( S ) typeof ( S ). GetConstructor ( BindingFlags . Instance | BindingFlags . NonPublic , null , new Type [ 0 ], new ParameterModifier [ 0 ]). Invoke ( null ); public static S CreatorInstance { get { return instance ; } } } public static T Példány { get { return SingletonCreator < T >. CreatorInstance ; } } } /// Singleton public class használata TestClass : Singleton < TestClass > { /// Meghívja a Singleton osztály védett konstruktorát private TestClass () { } public string TestProc () { return "Hello World" ; } }

Használhatja a szabványos lusta inicializálási szálbiztos Singleton megvalósítást is:

public class Singleton { /// A védett konstruktorra azért van szükség, hogy megakadályozzuk a Singleton osztály példányának létrehozását Protect Singleton () { } privát lezárt osztály SingletonCreator { private static readonly Singleton példány = new Singleton (); public static Singleton Instance { get { return instance ; } } } public static Singleton Instance { get { return SingletonCreator . Példa ; } } }

Ha nincs szükség nyilvános statikus metódusokra vagy tulajdonságokra (a Példány tulajdonságon kívül), akkor egyszerűsített változat is használható:

public class Singleton { private static readonly Singleton példány = new Singleton (); public static Singleton Instance { get { return instance ; } } /// A védett konstruktorra azért van szükség, hogy megakadályozzuk a Singleton osztály védett Singleton példányának létrehozását () { } }

Lusta inicializálási példa

névtér Singleton { public class Singleton { private static Singleton példány ; public static Singleton Instance { get { return instance ?? ( példány = new Singleton ()); } } védett Singleton () { } } }

PHP 4

Példa PHP4 -ben <?php class Singleton { function Singleton ( $directCall = true ) { if ( $directCall ) { trigger_error ( "Nem használható a konstruktor Singleton osztály létrehozásához. Static getInstance() metódus használata" , E_USER_ERROR ); } //TODO: Adja hozzá a fő konstruktor kódot ide } function & getInstance () { static $példány ; if ( ! is_object ( $példány ) ) { $class = __CLASS__ ; $példány = new $class ( false ); } return $példány ; } } //használat $test = & Singleton :: getInstance (); ?>

PHP 5

Példa PHP5 -ben <?php class Singleton { private static $példány ; // objektumpéldány privát függvény __construct (){ /* ... @return Singleton */ } // Védelem a létrehozástól új Singleton privát függvényen keresztül __clone () { /* ... @return Singleton */ } // Védelem a következőtől: létrehozás klónozással private function __wakeup () { /* ... @return Singleton */ } // Védelem a létrehozástól a nyilvános statikus függvény szerializálásának megszüntetésével getInstance () { // Az osztály egyetlen példányát adja vissza. @return Singleton if ( üres ( self :: $példány ) ) { self :: $példány = new self (); } return self :: $példány ; } nyilvános függvény doAction () { } } /* Alkalmazás */ Singleton :: getInstance () -> doAction (); // ?>

PHP 5.4

Példa a PHP5.4-ben <?php trait Singleton { private static $példány = null ; private function __construct () { /* ... @return Singleton */ } // Védelem a létrehozástól új Singleton privát függvényen keresztül __clone () { /* ... @return Singleton */ } // Védelem a létrehozástól privát klónon keresztül function __wakeup () { /* ... @return Singleton */ } // Védelem a létrehozástól a szerializálás megszüntetésével public static function getInstance () { return self :: $példány === null ? self :: $példány = new static () // Ha $példány 'null', akkor hozzon létre egy objektumot new self() : self :: $példány ; // Egyéb esetben egy létező objektum visszaadása } } /** * Foo osztály * @method static Foo getInstance() */ class Foo { use Singleton ; privát $bar = 0 ; public function incBar () { $this -> bar ++ ; } public function getBar () { return $this -> bar ; } } /* Jelentkezés */ $foo = foo :: getInstance (); $foo -> incBar (); var_dump ( $foo -> getBar ()); $foo = foo :: getInstance (); $foo -> incBar (); var_dump ( $foo -> getBar ()); ?>

Delphi

Delphi 2005 és újabb verziókhoz a következő példa megfelelő (nem szálbiztos):

Delphi példa type TSingleton = class strict private class var Példány : TSingleton ; public class függvény NewInstance : TObject ; felülbírálni ; vége ; osztályfüggvény TSingleton . _ NewInstance : TObject ; kezdődik , ha nincs hozzárendelve ( példány ) , akkor példány := TSingleton ( öröklött új példány ) ; Eredmény := Példány ; vége ;

Korábbi verziók esetén helyezze át az osztálykódot egy külön modulba, és Instancecserélje ki a deklarációt egy globális változó deklarációjára a szakaszában ( implementationa Delphi 7 előtt nem class varvoltak szakaszok strict private).

Dart

Dart példa

A Dart dokumentációjából származó gyári kivitelező alapján

class Singleton { static final Singleton _singleton = Singleton . _belső (); factory Singleton () { return _singleton ; } singleton . _belső (); }

Io

Io példa Singleton := Objektum klón Singleton klón := Singleton

Ruby

Példa Rubyban osztály Singleton def self . új @ példány ||= szuper vég

A szabványos könyvtár (Ruby 1.8 és újabb) tartalmazza a Singleton modult, amely még egyszerűbbé teszi a szinglitonok létrehozását:

szükséges 'singleton' osztály Foo include Singleton end a = Foo . A # Foo.new példány nem érhető el, a Foo osztály (egyetlen) # példányára való hivatkozás megszerzéséhez használja a Foo#instance metódust

Common Lisp

Példa a Common Lisp -ben ( defclass singleton-class () ;; a singleton mechanizmust megvalósító metaosztály (( példány :initform nil ))) ( defmethod validate- superclass (( class singleton-class ) ( superclass standard-class )) t ) ;;Engedélyezi az egytagú osztályok öröklését a normál osztályoktól ( defmethod validate- superclass (( class singleton-class ) ( superclass singleton-class )) t ) ) ; ( defmethod validate- superclass (( class standard-class ) ( superclass singleton-class )) nil ) ;;Tiltja meg a közönséges osztályok öröklődését szinglitől ( defmethod make-példány (( class singleton-class ) &key ) ( with-slots ( példány ) class ( vagy példány ( setf instance ( call-next-method ))))) ( defclass my-singleton-class () () ( :metaclass singleton-class ))

VB.NET

Példa a VB.NET -ben Modul Program Sub Main () Dim T1 As Singleton = Singleton . getInstance T1 . érték = 1000 Dim T2 As Singleton = Singleton . getInstance konzol . WriteLine ( T2 . Érték ) Konzol . Olvassa el () End Sub Vége modul Public Class Singleton Nyilvános érték egész számként 'Ne engedélyezze a Protected Sub konstruktor Új () End Sub Privát , nem örökölhető osztály SingletonCreator Privát , megosztott , csak olvasható m_példány Új Singletonként ( ) Nyilvános megosztott , csak olvasható tulajdonságpéldány () mint Singleton Get Return m_instance End Get End Property End Class Nyilvános megosztott , csak olvasható tulajdonság getInstance () Singletonként Get Return SingletonCreator . Példány vége Get End Propert végi osztály

Perl

Perl példa használd a v5.10-et ; _ szigorúan használd ; csomag Singleton ; sub new { # Statikus változó $példány # deklarálása és visszaadása a metódus végrehajtásának eredményeként new state $példány = bless {}; } csomag ; my $a = Singleton -> new ; my $b = Singleton -> new ; mondd "$a $b" ; # A $a és $b hivatkozások ugyanarra az objektumra mutatnak

Perl

Perl példa megváltoztathatatlan objektummal #!/usr/bin/perl -w használja a "say" funkciót ; szigorúan használd ; figyelmeztetések használata ; csomag Singleton { az én $példányom ; # osztálypéldány (statikus mező) # -- ** konstruktor ** -- sub new { my $class = shift ; ha nem ( $példány ) { # ellenőrizze, hogy van-e már példánya az $példány = { # osztályból, ha nem, hozzon létre egy újat, és írja be a köszönni kívánt személy nevét name => shift , }; áld $példány , $osztály ; } return $példány ; # adja vissza osztályunk egyetlen példányát } # -- ** hello ** -- sub hello { my ( $self ) = ( shift ); mondd: "Hello, $self->{name}" ; # köszöntsük az objektum tulajdonosát } } my $a = Singleton -> new ( 'Alex' ); # hozzon létre egy példányt egy Alex nevű osztályból my $b = Singleton -> new ( 'Barney' ); # ... most megpróbálok létrehozni egy másik példányt Barney számára $a -> hello (); # Hello, Alex # igen, hello Alex $b -> hello (); # Hello Alex # hoppá, Barney, bocsánat, micsoda félreértés...

ActionScript 3

ActionScript példa

Privát óra lehetőség:

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 ; } } } // Mivel az osztály ugyanabban a fájlban van deklarálva a // csomagon kívül, csak a Singleton osztály használhatja. class PrivateClass { public function PrivateClass () { } }

Kivételi lehetőség megadása:

package { public class Singleton { public static const példány : Singleton = new Singleton (); public function Singleton () { // Boolean(Singleton) hamis, ha az osztály // a statikus konstruktor végrehajtása előtt példányosodik if ( Singleton ) throw new Error ( "Class is singleton." ); } } }

Lehetőség hozzáférési változóval:

csomag { public class MySingleton { private static var _instance : MySingleton ; // Elérési változó privát static var _isConstructing : Boolean ; public function MySingleton () { if ( ! _isConstructing ) throw new Error ( "Singleton, használja a MySingleton.instance-ot" ); } public static function példány lekérése () : MySingleton { if ( _instance == null ) { _isConstructing = true ; _instance = új MySingleton (); _isConstructing = false ; } return _példány ; } } }

A privát osztály előnyei:

  • Ha közvetlenül a konstruktort próbálja használni, a fordító azonnal észleli a hibát. // Nem az egyetlen előnye ennek a módszernek
  • Az objektum kérésre létrejön.

A privát osztály lehetőségének hátránya:

  • A privát osztályt lecserélheti a sajátjával azonos néven.

A kivétel lehetőség előnyei:

  • Kevesebb kód.

CoffeeScript

Példa a CoffeeScriptben

Klasszikus megközelítés (Coffeescript ≠ 1,5)

class Singleton példány = undefined konstruktor : -> if instance ? vissza példány más példány = @ # Konstruktor kód konzol . assert ( új Singleton az új Singleton );

Megközelítés, amely azon a képességen alapul, hogy egy funkciót a testéből lehet elérni (Coffeescript ≠ 1,5)

class Singleton init = -> # konstruktor mint privát osztálymetódus # Konstruktorkód # ... # Cserélje ki a konstruktort, megtartva ezt (@) init = => @ return @ # Igazi kivitelező. Az init # return meghívására szolgál , különben ezt a (@) konstruktort adja vissza: -> return init . alkalmaz ( @ , argumentumok ) konzol . ( az új Singleton az új Singleton ) Megjegyzés: a valódi konstruktor megváltoztatása önmagáról, azaz. konstruktor : -> Singleton = => @ nem ad semmit, mert a kapott JavaScript kódban a konstruktor a helyi Singleton konstruktorra mutat, nem a Singleton osztályra.

Ha azonban névtereket használ, akkor ez a lehetőség lehetséges:

ns = {} ns osztály . Singleton konstruktor : -> # Konstruktor kód ns.Singleton == > @ konzol . Assert ( new ns . Singleton is new ns . Singleton )

JavaScript

JavaScript példa tokozással _

Változók lezárásokkal való elrejtésére épülő módszer. Bónuszként - privát módszerek és tulajdonságok deklarálása, amelyek mind a konstruktor, mind az "osztály" metódusok számára elérhetők lesznek.

const Singleton = ( function () { legyen példány ; // Privát módszerek és tulajdonságok // Konstruktorfüggvény Singleton ( ) { if ( példány ) return példány ; példány = ez ; } // Public Methods Singleton . prototípus . teszt = függvény () {}; return Singleton ; })(); konzol . log ( new Singleton () === new Singleton ());

A változó elrejtése nélkül van egy egyszerű megoldás, amely azon alapul, hogy a Singleton függvény egy objektum. A hátránya a példánytulajdonság megváltoztatásának lehetősége az osztályon kívül:

function Singleton () { const instance = Singleton . példány ; if ( példány ) return instance ; singleton . példány = ez ; } singleton . prototípus . teszt = függvény () {}; konzol . log ( new Singleton () === new Singleton ());

A legrövidebb lehetőség.

const Singleton = new ( function () { const példány = this ; return function () { return példány ; }; })(); konzol . log ( new Singleton () === new Singleton ());

JS osztály statikus privát mezőinek használata:

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

Objective-C

Példa az Objective-C- ben

singleton.h

@interface Singleton  : NSObject { } + ( Singleton * ) sharedInstance ; @vége

singleton.m

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

Vagy (csak OS X 10.6+, iOS 4.0+ esetén):

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

Swift

Gyors példa class Singleton { static let shared = Singleton () private init () { } }

Scala, Kotlin

Példa a Scalában és a Kotlinban object Singleton {} // "objektum" kulcsszó létrehoz egy osztályt, amely alapértelmezés szerint megvalósítja a "singleton" mintát

Lásd még

Irodalom

  • Alan Shalloway, James R. Trott tervezési minták. Az objektum-orientált tervezés új megközelítése = Design Patterns Explained: Új perspektíva az objektum-orientált tervezéshez. - M .: "Williams", 2002. - S. 288. - ISBN 0-201-71594-5 .
  • Eric Freeman, Elizabeth Freeman. Tervezési minták = Head First Design Patterns. - Szentpétervár. : Péter, 2011. - 656 p. - ISBN 978-5-459-00435-9 .

Linkek

Jegyzetek