Singleton mønster - Singleton pattern
I softwareteknik er singleton -mønsteret et softwaredesignmønster, der begrænser instantiering af en klasse til en "enkelt" forekomst. Dette er nyttigt, når nøjagtigt ét objekt er nødvendigt for at koordinere handlinger på tværs af systemet.
Udtrykket kommer fra det matematiske begreb om en singleton .
Oversigt
Singleton designmønsteret er et af de tre velkendte "Gang of Four" designmønstre, der beskriver, hvordan man løser tilbagevendende designproblemer til at designe fleksibel og genanvendelig objektorienteret software med det formål at gøre det lettere at implementere, ændre, teste og genbruge objekter.
Singleton -designmønsteret løser problemer ved at tillade det at:
- Sørg for, at en klasse kun har én forekomst
- Få let adgang til den eneste instans af en klasse
- Kontroller dens instantiering
- Begræns antallet af forekomster
- Få adgang til en global variabel
Singleton -designmønsteret beskriver, hvordan man løser sådanne problemer:
- Skjul konstruktører i klassen .
- Definer en offentlig statisk operation (
getInstance()
), der returnerer den eneste forekomst af klassen.
I det væsentlige tvinger singletonmønsteret det til at være ansvarligt for at sikre, at det kun instantieres én gang. En skjult konstruktør - erklæret private
eller - protected
sikrer, at klassen aldrig kan instantieres uden for klassen. Den offentlige statiske operation kan tilgås ved hjælp af klassens navn og betjeningsnavn, f.eks Singleton.getInstance()
.
Almindelige anvendelser
- Den abstrakte fabrik , fabriksmetode , bygherre og prototypemønstre kan bruge singletons.
- Facadeobjekter er ofte singletoner, fordi der kun kræves et facadeobjekt.
- Statsobjekter er ofte singletoner.
- Singletons foretrækkes ofte frem for globale variabler, fordi:
- De forurener ikke det globale navnerum (eller, på sprog med indlejrede navnerum, deres indeholdende navnerum) med unødvendige variabler.
- De tillader doven allokering og initialisering, hvorimod globale variabler på mange sprog altid vil forbruge ressourcer.
Logning er et klassisk eksempel på en singleton.
Kritik
Kritikere anser singleten for at være et antimønster, idet den ofte bruges i scenarier, hvor den ikke er gavnlig, fordi den ofte indfører unødvendige restriktioner i situationer, hvor en singleton-klasse ikke ville være gavnlig, og derved introducere global tilstand i en applikation.
Fordi en singleton kan nås overalt med noget uden at skulle bruge nogen parametre, ville eventuelle afhængigheder ikke umiddelbart være synlige for udviklere. Derfor skulle udviklere kende "den indre funktion af kode for at kunne bruge den korrekt".
Singletons overtræder også princippet om enkeltansvar , fordi de ikke kun er ansvarlige for singlettons normale opgave, det skal også sikre, at kun en instantieres; Bemærk, at dette er baseret på en "klassisk" singleton -definition, hvor det er ansvarligt for at håndhæve sin egen unikhed gennem f.eks. en statisk getInstance()
metode.
En anden ulempe er, at singletons er svære at teste, fordi de bærer global tilstand i programmets varighed. Specielt fordi enhedstest kræver løst koblede klasser for at isolere, hvad der testes. Når en bestemt klasse desuden interagerer med en singleton, bliver denne klasse og singletonen tæt forbundet , hvilket gør det umuligt at teste klassen alene uden også at teste singleton.
Implementeringer
Implementeringer af singleton -mønsteret skal:
- Sørg for, at der kun findes én forekomst af singleton -klassen; og
- Giv global adgang til denne instans.
Typisk gøres dette ved:
- Deklarere alle konstruktører i klassen til at være private ; og
- Tilvejebringelse af en statisk metode, der returnerer en reference til forekomsten.
Instansen lagres normalt som en privat statisk variabel ; forekomsten oprettes, når variablen initialiseres, på et tidspunkt før den statiske metode først kaldes.
Java
Singleton -implementering i Java :
public class Coin {
private static final int ADD_MORE_COIN = 10;
private int coin;
private static Coin instance = new Coin(); // eagerly loads the singleton
private Coin(){
// private to prevent anyone else from instantiating
}
public static Coin getInstance() {
return instance;
}
public int getCoin() {
return coin;
}
public void addMoreCoin() {
coin += ADD_MORE_COIN;
}
public void deductCoin() {
coin--;
}
}
public final class Singleton {
private static final Singleton INSTANCE = new Singleton();
private Singleton() {}
public static Singleton getInstance() {
return INSTANCE;
}
}
Dårlig initialisering
En singleton -implementering kan bruge doven initialisering , hvor forekomsten oprettes, når den statiske metode først påberåbes. Hvis den statiske metode kan kaldes fra flere tråde samtidigt, kan det være nødvendigt at træffe foranstaltninger for at forhindre løbstilstande, der kan resultere i oprettelse af flere forekomster. Følgende er en trådsikker implementering, der bruger doven initialisering med dobbeltkontrolleret låsning , skrevet i Java. For at undgå synkroniseringsomkostningerne samtidig med, at der holdes dovne initialisering med trådsikkerhed, er den foretrukne tilgang i Java at bruge initialiserings-on-demand indehaverformatet .
public final class Singleton {
private static volatile Singleton instance = null;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) {
synchronized(Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
Python
class Singleton:
__instance = None
def __new__(cls, *args):
if cls.__instance is None:
cls.__instance = object.__new__(cls, *args)
return cls.__instance
C ++
Som af C ++ 11 , statisk lokal variabel initialisering er tråd-safe og finder sted efter det første påkaldelse. Dette er et sikrere alternativ end et navneområde eller en klasseomfattet statisk variabel.
class Singleton {
public:
static Singleton& GetInstance() {
// Allocate with `new` in case Singleton is not trivially destructible.
static Singleton* singleton = new Singleton();
return *singleton;
}
private:
Singleton() = default;
// Delete copy/move so extra instances can't be created/moved.
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
Singleton(Singleton&&) = delete;
Singleton& operator=(Singleton&&) = delete;
};
C#
Singleton -implementering i C# :
public sealed class Singleton
{
public static Singleton Instance { get; } = new Singleton();
private Singleton() { }
}
I C# kan du også bruge statiske klasser til at oprette singletons, hvor selve klassen er singleton.
public static class Singleton
{
public static MyOtherClass Instance { get; } = new MyOtherClass();
}
Enhed
Singletons kan være et nyttigt værktøj, når de udvikler sig med Unity takket være, hvordan klasser instantieres. Denne metode foretrækkes frem for at konstruktør skjuler sig, da det er muligt at instantiere et objekt med en skjult konstruktør i Unity. For at forhindre en forekomst i at blive overskrevet, skal der udføres en kontrol for at sikre, at forekomsten er det null
. Hvis det ikke er null, skal det GameObject
indeholdende det krænkende script ødelægges.
Hvis andre komponenter er afhængige af singleton, skal scriptudførelsesordren ændres for at sikre, at komponenten, der definerer singleton, udføres først.
class Singleton : MonoBehaviour
{
public static Singleton Instance { get; private set; }
private void Awake()
{
if (Instance != null && Instance != this) {
Destroy(this.gameObject);
} else {
Instance = this;
}
}
}
Bemærk, at det også er muligt at implementere en singleton ved kun at fjerne det krænkende script, ikke GameObject
selve, ved i stedet at ringe Destroy(this)
.
Dart
Singleton -implementering i Dart :
class Singleton {
Singleton._();
static Singleton get instance => Singleton._();
}
PHP
Singleton -implementering i PHP :
class Singleton
{
private static $instance = null;
private function __construct() {}
public static function getInstance(): self
{
if (null === self::$instance) {
self::$instance = new self();
}
return self::$instance;
}
}
Kotlin
Kotlin objekt søgeord erklærer en singleton klasse
object Coin {
private var coin: Int = 0
fun getCoin():Int {
return coin
}
fun addCoin() {
coin += 10
}
fun deductCoin() {
coin--
}
}
Pascal
En trådsikker implementering af en singleton i Pascal :
unit SingletonPattern;
interface
type
TTest = class sealed
strict private
FCreationTime: TDateTime;
public
constructor Create;
property CreationTime: TDateTime read FCreationTime;
end;
function GetInstance: TTest;
implementation
uses
SysUtils
, SyncObjs
;
var
FCriticalSection: TCriticalSection;
FInstance: TTest;
function GetInstance: TTest;
begin
FCriticalSection.Acquire;
try
if not Assigned(FInstance) then
FInstance := TTest.Create;
Result := FInstance;
finally
FCriticalSection.Release;
end;
end;
constructor TTest.Create;
begin
inherited Create;
FCreationTime := Now;
end;
initialization
FCriticalSection := TCriticalSection.Create;
finalization
FreeAndNil(FCriticalSection);
end.
Anvendelse:
procedure TForm3.btnCreateInstanceClick(Sender: TObject);
var
i: integer;
begin
for i := 0 to 5 do
ShowMessage(DateTimeToStr(GetInstance.CreationTime));
end;
Se også
Referencer
eksterne links
- Komplet artikel " Java Singleton -mønster forklaret "
- Fire forskellige måder at implementere singleton på i Java " Måder at implementere singleton på i Java "
- Boguddrag: Implementering af Singleton -mønsteret i C# af Jon Skeet
- Singleton hos Microsoft mønstre og praksis Developer Center
- IBM-artikel " Dobbeltkontrolleret låsning og Singleton-mønsteret " af Peter Haggar
- Geary, David (25. april 2003). "Sådan navigerer du i det vildledende enkle Singleton -mønster" . Java designmønstre. JavaWorld . Hentet 2020-07-21 .
- Google Singleton Detector (analyserer Java -bytecode for at registrere singletons)