Singleton mønster - Singleton pattern

Et klassediagram, der eksemplificerer singletonmønsteret.

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 privateeller - protectedsikrer, 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

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:

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 GameObjectindeholdende 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 GameObjectselve, 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