logo

Singleton-methode ontwerppatroon

Singleton Pattern is waarschijnlijk het meest gebruikte ontwerppatroon. Het is een eenvoudig patroon, gemakkelijk te begrijpen en te gebruiken. Soms wordt het in overmaat gebruikt en in scenario's waarin het niet nodig is. In dergelijke gevallen wegen de nadelen van het gebruik ervan zwaarder dan de voordelen die het met zich meebrengt. Om deze reden wordt het singleton-patroon soms beschouwd als een antipatroon of patroon singleton .

Singleton-methode-ontwerppatroon



Belangrijke onderwerpen voor het Singleton Method Design Pattern

1. Wat is het Singleton Method-ontwerppatroon?

De Singleton-methode of Singleton Design-patroon is een van de eenvoudigste ontwerppatronen. Het zorgt ervoor dat een klasse slechts één instantie heeft en biedt een globaal toegangspunt daartoe.

2. Wanneer gebruik je het Singleton Method Design Pattern?

Gebruik de Singleton-methode Design Pattern wanneer:



  • Er moet precies één instantie van een klasse zijn en deze moet toegankelijk zijn voor clients vanaf een bekend toegangspunt.
  • Wanneer de enige instantie uitbreidbaar moet zijn door middel van subklassen en clients een uitgebreide instantie moeten kunnen gebruiken zonder wijzigingen aan te brengen
  • Singleton-klassen worden gebruikt voor logboekregistratie, stuurprogrammaobjecten, caching, threadpool en databaseverbindingen.

3. Initialisatietypen van Singleton

De Singleton-klasse kan op twee manieren worden geïnstantieerd:

FCF's
  • Vroege initialisatie: Bij deze methode wordt de klasse geïnitialiseerd, ongeacht of deze moet worden gebruikt of niet. Het belangrijkste voordeel van deze methode is de eenvoud ervan. Je start de les op het moment dat de les wordt geladen. Het nadeel is dat de klasse altijd wordt geïnitialiseerd, ongeacht of deze wordt gebruikt of niet.
  • Luie initialisatie: Bij deze methode wordt de klasse alleen geïnitialiseerd als dit nodig is. Het kan u ervan weerhouden de klasse te instantiëren wanneer u deze niet nodig heeft. Over het algemeen wordt luie initialisatie gebruikt wanneer we een singleton-klasse maken.

4. Belangrijk onderdeel van het ontwerppatroon van de Singleton-methode:

Key-Component-of-Singleton-Method-Design-Pattern-(1)

tekenreeksopmaak java

4.1. Statisch lid:

Het Singleton-patroon of patroon Singleton maakt gebruik van een statisch lid binnen de klasse. Dit statische lid zorgt ervoor dat geheugen slechts één keer wordt toegewezen, waardoor de enkele instantie van de Singleton-klasse behouden blijft.



Java
// Static member to hold the single instance private static Singleton instance;>

4.2. Particuliere constructeur:

Het Singleton-patroon of patroon singleton bevat een privéconstructor, die dient als een barricade tegen externe pogingen om exemplaren van de Singleton-klasse te maken. Dit zorgt ervoor dat de klasse controle heeft over het instantiatieproces.

Java
// Private constructor to // prevent external instantiation class Singleton {  // Making the constructor as Private  private Singleton()  {  // Initialization code here  } }>

4.3. Statische fabrieksmethode:

Een cruciaal aspect van het Singleton-patroon is de aanwezigheid van een statische fabrieksmethode. Deze methode fungeert als een gateway en biedt een globaal toegangspunt tot het Singleton-object. Wanneer iemand een exemplaar aanvraagt, maakt deze methode een nieuw exemplaar (als er geen bestaat) of retourneert het bestaande exemplaar naar de aanroeper.

Java
// Static factory method for global access public static Singleton getInstance() {  // Check if an instance exists  if (instance == null) {  // If no instance exists, create one  instance = new Singleton();  }  // Return the existing instance  return instance; }>

5. Implementatie van het Singleton Method Design Pattern

De implementatie van een Singleton Design Pattern of Pattern Singleton wordt beschreven in het volgende klassendiagram:

Schermafbeelding-2023-12-07-174635

Implementatie van het Singleton Method Design Pattern

De implementatie van het Singleton Design-patroon is heel eenvoudig en bestaat uit één klasse. Om ervoor te zorgen dat de singleton-instantie uniek is, moeten alle singleton-constructors privé worden gemaakt. Globale toegang vindt plaats via een statische methode die globaal toegang kan krijgen tot een enkele instantie, zoals weergegeven in de code.

Java
/*package whatever //do not write package name here */ import java.io.*; class Singleton {  // static class  private static Singleton instance;  private Singleton()  {  System.out.println('Singleton is Instantiated.');  }  public static Singleton getInstance()  {  if (instance == null)  instance = new Singleton();  return instance;  }  public static void doSomething()  {  System.out.println('Somethong is Done.');  } } class GFG {  public static void main(String[] args)  {  Singleton.getInstance().doSomething();  } }>

Uitvoer
Singleton is Instantiated. Somethong is Done.>

Met de getInstance methode controleren we of de instance null is. Als de instantie niet nul is, betekent dit dat het object eerder is gemaakt; anders maken we het met de nieuwe operator.

6. Verschillende manieren om het Singleton Method Design Pattern te implementeren

Soms hebben we slechts één exemplaar van onze klasse nodig, bijvoorbeeld een enkele DB-verbinding die door meerdere objecten wordt gedeeld, omdat het maken van een afzonderlijke DB-verbinding voor elk object kostbaar kan zijn. Op dezelfde manier kan er één configuratiemanager of foutmanager in een applicatie zijn die alle problemen afhandelt in plaats van meerdere managers te creëren.

Klassiek-implementatie

Laten we verschillende ontwerpopties bekijken voor het implementeren van een dergelijke klasse. Als je goed overweg kunt met statische klassenvariabelen en toegangsmodificatoren, zou dit geen moeilijke taak moeten zijn.

Methode 1 – Klassieke implementatie || Maak getInstance() statisch om te implementeren Singleton-methode ontwerppatroon

Java
// Classical Java implementation of singleton // design pattern class Singleton {  private static Singleton obj;  // private constructor to force use of  // getInstance() to create Singleton object  private Singleton() {}  public static Singleton getInstance()  {  if (obj == null)  obj = new Singleton();  return obj;  } }>

Hier hebben we verklaard getInstance() statisch zodat we het kunnen aanroepen zonder de klasse te instantiëren. De eerste keer getInstance() wordt genoemd, het creëert een nieuw singleton-object en daarna retourneert het gewoon hetzelfde object.

Java-datum naar tekenreeks

Opmerking: Singleton obj wordt pas gemaakt als we het nodig hebben en de getInstance() methode. Dit wordt luie instantiatie genoemd. Het grootste probleem met de bovenstaande methode is dat deze niet thread-safe is. Beschouw de volgende uitvoeringsvolgorde.

Deze uitvoeringsreeks creëert twee objecten voor de singleton. Daarom is deze klassieke implementatie niet thread-safe.

Methode 2 || Zorg ervoor dat getInstance() gesynchroniseerd wordt om te implementeren Singleton-methode ontwerppatroon

Java
// Thread Synchronized Java implementation of // singleton design pattern class Singleton {  private static Singleton obj;  private Singleton() {}  // Only one thread can execute this at a time  public static synchronized Singleton getInstance()  {  if (obj == null)  obj = new Singleton();  return obj;  } }>

Hier zorgt het gebruik van gesynchroniseerd ervoor dat slechts één thread tegelijk kan worden uitgevoerd getInstance() . Het grootste nadeel van deze methode is dat het elke keer synchroniseren tijdens het maken van het singleton-object duur is en de prestaties van uw programma kan verminderen. Echter, als de prestaties van getInstance() is niet essentieel voor uw toepassing. Deze methode biedt een schone en eenvoudige oplossing.

Java programmeert priemgetallen

Methode 3 – Enthousiaste instantiatie || Op statische initialisatie gebaseerde implementatie van singleton-ontwerppatroon

Java
// Static initializer based Java implementation of // singleton design pattern class Singleton {  private static Singleton obj = new Singleton();  private Singleton() {}  public static Singleton getInstance() { return obj; } }>

Hier hebben we een exemplaar van een singleton in een statische initialisator gemaakt. JVM voert een statische initialisatie uit wanneer de klasse wordt geladen en daarom is dit gegarandeerd thread-safe. Gebruik deze methode alleen als uw singleton-klasse licht is en tijdens de uitvoering van uw programma wordt gebruikt.

Methode 4 – Meest efficiënt || Gebruik Double Checked Locking om het singleton-ontwerppatroon te implementeren

Als u goed oplet zodra een object is gemaakt, is synchronisatie niet langer nuttig, omdat obj nu niet nul zal zijn en elke reeks bewerkingen tot consistente resultaten zal leiden. We zullen dus slechts één keer de vergrendeling van de getInstance() verkrijgen als de obj nul is. Zo synchroniseren we alleen de eerste doorgang, precies wat we willen.

Java
// Double Checked Locking based Java implementation of // singleton design pattern class Singleton {  private static volatile Singleton obj = null;  private Singleton() {}  public static Singleton getInstance()  {  if (obj == null) {  // To make thread safe  synchronized (Singleton.class)  {  // check again as multiple threads  // can reach above step  if (obj == null)  obj = new Singleton();  }  }  return obj;  } }>

Wij hebben het obj verklaard vluchtig wat ervoor zorgt dat meerdere threads de obj-variabele correct aanbieden wanneer deze wordt geïnitialiseerd naar de Singleton-instantie. Deze methode vermindert drastisch de overhead van het elke keer aanroepen van de gesynchroniseerde methode.

7. Gebruiksvoorbeeld van de Pattern Singleton-methode

  • Databaseverbindingen: In toepassingen waarbij het maken en beheren van databaseverbindingen een dure operatie is, kan een Singleton worden gebruikt om één databaseverbinding in de hele toepassing te onderhouden.
  • Configuratiebeheer: Wanneer u globale configuratie-instellingen heeft waartoe verschillende componenten van de applicatie toegang moeten hebben, kan een Singleton-configuratiemanager één enkel toegangspunt voor deze instellingen bieden.
  • GUI-componenten: Voor grafische gebruikersinterfacecomponenten (GUI) of controllers kan een Singleton helpen bij het beheren van de status en acties van de gebruikersinterface, waardoor één enkel controlepunt ontstaat.
  • Apparaatbeheerders: In ingebedde systemen of applicaties die interactie hebben met hardwareapparaten, kan een Singleton worden gebruikt om de toegang tot hardwareapparaten te beheren en te controleren om conflicten te voorkomen.
  • Afdrukservice: In systemen waarbij documenten of rapporten moeten worden afgedrukt, kan een afdrukservice van Singleton afdruktaken coördineren en beheren, waardoor een efficiënt gebruik van afdrukbronnen wordt gegarandeerd.

8. Voordelen van het Singleton Method-ontwerppatroon:

  • Lost naambotsingen op: In scenario's waarin één enkel controlepunt nodig is om naamconflicten of botsingen te voorkomen, zorgt het Singleton-patroon ervoor dat er slechts één exemplaar is met een unieke naam.
  • Enthousiaste of luie initialisatie: Het Singleton-patroon ondersteunt zowel enthousiaste initialisatie (het creëren van de instantie wanneer de klasse wordt geladen) als luie initialisatie (het creëren van de instantie wanneer deze voor het eerst wordt aangevraagd), waardoor flexibiliteit wordt geboden op basis van de gebruikssituatie.
  • Draadveiligheid: Correct geïmplementeerde Singleton-patronen kunnen threadveiligheid bieden, waardoor wordt verzekerd dat de instantie atomair wordt gemaakt en dat meerdere threads niet per ongeluk dubbele instanties creëren.
  • Verminderde geheugenvoetafdruk: In toepassingen waarbij het gebruik van hulpbronnen van cruciaal belang is, kan het Singleton-patroon bijdragen aan een kleinere geheugenvoetafdruk door ervoor te zorgen dat er slechts één exemplaar van de klasse is.

9. Nadelen van het Singleton-ontwerppatroon

  • Moeilijkheden bij het testen: Omdat Singletons een mondiale status introduceren, kan het testen van eenheden een uitdaging worden. Het afzonderlijk testen van één component kan ingewikkelder zijn als het afhankelijk is van een Singleton, aangezien de staat van de Singleton de uitkomst van tests kan beïnvloeden.
  • Gelijktijdigheidsproblemen: In een omgeving met meerdere threads kunnen er problemen optreden met betrekking tot het maken en initialiseren van de Singleton-instantie. Als meerdere threads tegelijkertijd proberen de Singleton te maken, kan dit tot raceomstandigheden leiden.
  • Beperkte uitbreidbaarheid: Het Singleton-patroon kan code minder uitbreidbaar maken. Als u later besluit dat u meerdere exemplaren van de klasse nodig heeft of als u de instantiatielogica wilt wijzigen, kan dit aanzienlijke refactoring vereisen.
  • Mondiale afhankelijkheid: Het Singleton-patroon creëert een mondiale afhankelijkheid, waardoor het moeilijker wordt om de Singleton te vervangen door een alternatieve implementatie of om afhankelijkheidsinjectie te gebruiken voor het leveren van instances.
  • Moeilijk te subklasse: Het indelen van een Singleton kan een uitdaging zijn. Omdat de constructor doorgaans privé is, vereist het uitbreiden van een Singleton extra zorg en volgt mogelijk niet de standaard overervingspatronen.
  • Levenscyclus management: Het Singleton-patroon verwerkt mogelijk geen scenario's waarin de instantie expliciet moet worden vernietigd of opnieuw moet worden ingesteld. Het beheren van de levenscyclus van de Singleton kan een zorg worden.
  • Wereldwijd misbruik van toegangspunten: Hoewel een mondiaal toegangspunt een voordeel is, kan er ook misbruik van worden gemaakt. Ontwikkelaars kunnen in de verleiding komen om de Singleton voor alles te gebruiken, wat leidt tot een overmatig gebruik van de mondiale status en een minder modulair ontwerp.

10. Conclusie

Het is belangrijk dat sommige klassen precies één instantie hebben. Hoewel er veel printers in een systeem kunnen zijn, mag er slechts één printerspooler zijn. Er zou slechts één bestandssysteem en één vensterbeheerder moeten zijn. Een digitaal filter heeft één A/D-omzetter. Een boekhoudsysteem zal bestemd zijn voor de dienstverlening aan één bedrijf. Hoe zorgen we ervoor dat een klasse slechts één instantie heeft en dat de instantie gemakkelijk toegankelijk is? Een globale variabele maakt een object toegankelijk, maar weerhoudt u er niet van om meerdere objecten te instantiëren.

Een betere oplossing is om de klasse zelf verantwoordelijk te maken voor het bijhouden van zijn enige instantie. De klasse kan ervoor zorgen dat er geen andere instantie kan worden gemaakt (door verzoeken om nieuwe objecten te maken te onderscheppen), en kan een manier bieden om toegang te krijgen tot de instantie. Dit is het Singleton-patroon.