Singleton mönster - Singleton pattern
Inom mjukvaruteknik är singletonmönstret ett mjukvarudesignmönster som begränsar instansering av en klass till en "enda" instans. Detta är användbart när exakt ett objekt behövs för att koordinera åtgärder i hela systemet.
Termen kommer från det matematiska konceptet singleton .
Översikt
Singleton-mönstret är ett av de tjugotre tre välkända "Gang of Four" -mönstren som beskriver hur man löser återkommande designproblem för att designa flexibel och återanvändbar objektorienterad programvara i syfte att göra det enklare att implementera, ändra, testa och återanvända objekt.
Singleton -mönstret löser problem genom att låta det:
- Se till att en klass bara har en instans
- Få enkelt tillgång till den enda instansen av en klass
- Kontrollera dess instans
- Begränsa antalet instanser
- Få tillgång till en global variabel
Singleton -mönstret beskriver hur man löser sådana problem:
- Dölj konstruktörerna i klassen .
- Definiera en offentlig statisk operation (
getInstance()) som returnerar den enda instansen av klassen.
I huvudsak tvingar singletonmönstret att ansvara för att det bara instanseras en gång. En dold konstruktör - deklarerad privateeller - protectedförsäkrar att klassen aldrig kan instanseras utanför klassen. Den public static operation kan nås med hjälp av klassnamnet och drift namn, till exempel Singleton.getInstance().
Vanliga användningsområden
- Den abstrakta fabriken , fabriksmetoden , byggmästaren och prototypmönstren kan använda singletoner.
- Fasadobjekt är ofta singletoner eftersom endast ett fasadobjekt krävs.
- Statliga föremål är ofta singletoner.
- Singletoner föredras ofta framför globala variabler eftersom:
- De förorenar inte det globala namnutrymmet (eller, på språk med kapslade namnutrymmen, deras innehållande namnutrymme) med onödiga variabler.
- De tillåter lat tilldelning och initialisering, medan globala variabler på många språk alltid kommer att konsumera resurser.
Loggning är ett klassiskt exempel på en singleton.
Kritik
Kritiker anser att singleton är ett antimönster genom att det ofta används i scenarier där det inte är fördelaktigt eftersom det ofta inför onödiga restriktioner i situationer där en singleton-klass inte skulle vara till nytta, och därigenom inför global status i en applikation.
Eftersom en singleton dessutom kan nås var som helst av någonting utan att behöva använda några parametrar, skulle alla beroenden inte vara direkt synliga för utvecklare. Följaktligen skulle utvecklare behöva känna till "kodens inre funktion för att kunna använda den korrekt".
Singletons bryter också mot principen om ett enda ansvar , eftersom de inte bara är ansvariga för singletons normala uppgift, det måste också se till att endast en är instanserad; Observera att detta bygger på en "klassisk" singleton -definition där den är ansvarig för att upprätthålla sin egen unikhet genom till exempel en statisk getInstance()metod.
En annan nackdel är att singletons är svåra att testa eftersom de bär globalt tillstånd under programmets varaktighet. Specifikt eftersom enhetstestning kräver löst kopplade klasser för att isolera det som testas. Dessutom, när en viss klass interagerar med en singleton, blir den klassen och singleton tätt kopplade , vilket gör det omöjligt att testa klassen på egen hand utan att också testa singleton.
Implementeringar
Implementeringarna av singletonmönstret måste:
- Se till att bara en instans av singleton -klassen någonsin existerar; och
- Ge global åtkomst till den instansen.
Normalt görs detta av:
- Förklarar alla konstruktörer i klassen att vara privata ; och
- Tillhandahåller en statisk metod som returnerar en referens till förekomsten.
Instansen lagras vanligtvis som en privat statisk variabel ; instansen skapas när variabeln initialiseras, någon gång innan den statiska metoden först anropas.
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;
}
}
Lat initialisering
En singleton -implementering kan använda lat initialisering , där instansen skapas när den statiska metoden först anropas. Om den statiska metoden kan anropas från flera trådar samtidigt kan det behöva vidtas åtgärder för att förhindra tävlingsförhållanden som kan leda till att flera instanser skapas. Följande är en trådsäker implementering med lat initialisering med dubbelkontrollerad låsning , skriven i Java. För att undvika synkroniseringsomkostnader samtidigt som lat initialisering med trådsäkerhet hålls är det föredragna tillvägagångssättet i Java att använda id-id för initialisering på begäran .
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;
}
}
Pytonorm
class Singleton:
__instance = None
def __new__(cls, *args):
if cls.__instance is None:
cls.__instance = object.__new__(cls, *args)
return cls.__instance
C ++
Från och med C ++ 11 är initialisering av statisk lokal variabel trådsäker och inträffar efter den första anropet. Detta är ett säkrare alternativ än en namnrymd eller klassisk omfattande 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 också använda statiska klasser för att skapa singletons, där själva klassen är singleton.
public static class Singleton
{
public static MyOtherClass Instance { get; } = new MyOtherClass();
}
Enhet
Singletons kan vara ett användbart verktyg när de utvecklas med Unity tack vare hur klasser instanseras. Denna metod föredras framför konstruktörsgömning , eftersom det är möjligt att instantiera ett objekt med en dold konstruktör i Unity. För att förhindra att en instans skrivs över måste en kontroll utföras för att säkerställa att instansen är det null. Om det inte är null GameObjectbör det innehållande det kränkande skriptet förstöras.
Om andra komponenter är beroende av singleton, bör exekveringsordern för scriptet ändras för att säkerställa att komponenten som definierar singleton körs 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;
}
}
}
Observera att det också är möjligt att implementera en singleton genom att bara ta bort det kränkande skriptet, inte GameObjectsjälva, genom att istället ringa Destroy(this).
Pil
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 nyckelord förklarar en singleton klass
object Coin {
private var coin: Int = 0
fun getCoin():Int {
return coin
}
fun addCoin() {
coin += 10
}
fun deductCoin() {
coin--
}
}
Pascal
En trådsäker implementering av 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.
Användande:
procedure TForm3.btnCreateInstanceClick(Sender: TObject);
var
i: integer;
begin
for i := 0 to 5 do
ShowMessage(DateTimeToStr(GetInstance.CreationTime));
end;
Se även
Referenser
externa länkar
- Komplett artikel " Java Singleton -mönster förklarat "
- Fyra olika sätt att implementera singleton i Java " Sätt att implementera singleton i Java "
- Bokutdrag: Implementering av Singleton -mönstret i C# av Jon Skeet
- Singleton på Microsofts mönster och metoder Developer Center
- IBM-artikeln " Dubbelkontrollerad låsning och Singleton-mönstret " av Peter Haggar
- Geary, David (25 april 2003). "Hur man navigerar i det bedrägligt enkla Singleton -mönstret" . Java designmönster. JavaWorld . Hämtad 2020-07-21 .
- Google Singleton Detector (analyserar Java -bytekod för att upptäcka singletons)