Sunteți pe pagina 1din 13

Singleton design pattern: Soluții eficiente în

crearea de obiecte unice

Student: Cătălin-Andrei Brînzei


Cuprins

1. Introducere
2. Analogie din realitate
3. Problema
4. Solouția
5. Aplicabilitate
6. Implementare
7. Exemplu
8. Avantaje și dezavantaje
9. Bibliografie
Intrdoducere

Singleton este un design pattern creațional care asigură că o


clasă are doar o instanță și oferă un punct global de acces la
această instanță. Acest pattern poate fi util în cazul în care dorim
să controlăm accesul la un resursă comună, cum ar fi o bază de
date sau un fișier.
Analogie din realitate

Să ne imaginăm că o imprimantă reprezintă o clasă


Singleton. Într-un birou cu mai mulți utilizatori, există o singură
imprimantă pe care toți angajații o folosesc. Indiferent de câți
angajați doresc să tipărească documente, ei se conectează la
aceeași imprimantă globală.
Problema

Singleton rezolvă două probleme simultan, încălcând


Principiul Responsabilității Unice:

1. Asigură că o clasă are doar o singură instanță: În cazul


imprimantei, dorim să avem o singură instanță a aceleiași
imprimante, pentru a evita conflictele de resurse și pentru a
gestiona eficient tipărirea.

2. Oferă un punct global de acces la acea instanță: Singleton


permite fiecărui utilizator să acceseze imprimanta globală,
oferindu-le un punct comun de conectare pentru tipărire.
Soluția

Implementările Singleton au două pași comuni:


• Se face constructorul implicit privat pentru a împiedica alte
obiecte să utilizeze operatorul new cu clasa Singleton.
• Se creează o metodă statică de creare care acționează ca un
constructor. Această metodă apelează constructorul privat
pentru a crea un obiect și îl salvează într-un câmp static.
Toate apelurile ulterioare ale acestei metode returnează
obiectul memorat.

Aplicabilitate

Se folosește Singleton atunci când:

• O resursă, cum ar fi o imprimantă, ar trebui să aibă o


singură instanță disponibilă pentru toți utilizatorii.
• Ai nevoie de un control strict asupra accesului la resursa
comună, evitând suprafolosirea sau conflictele.
Implementare

Implementarea design pattern-ului Singleton presupune


respectarea unor pași esențiali pentru a asigura că o clasă are o
singură instanță și oferă un punct global de acces la acea
instanță. În acest context, se vor detalia pașii necesari pentru a
realiza o implementare eficientă a acestui pattern.

1. Se adaugă un câmp privat static în clasa Singleton


pentru stocarea instanței singleton.

• Acest câmp va reține unica instanță a clasei.

2. Se declară o metodă publică statică de creare pentru a


obține instanța singleton.

• Această metodă va crea instanța la prima apelare și va returna


aceeași instanță în apelurile ulterioare.

3. Se implementează "inițializarea leneșă" în interiorul


metodei statice.

• Metoda de creare verifică dacă instanța a fost deja creată și, în caz
contrar, o creează.
4. Se face constructorul clasei privat.

• Constructorul privat împiedică alte obiecte să creeze instanțe


directe ale clasei.

5. Se parcurge codul clientului și se înlocuiesc apelurile


directe la constructorul singleton-ului cu apeluri la metoda
sa statică de creare.

• Clientul trebuie să obțină instanța singleton prin apelarea metodei


statice de creare.

Exemplu

Există 2 tipuri de Singleton: Naive si Thread-safe.


1. Naïve singleton: Implementarea simplă a Singleton, dar
care nu funcționează correct într-un mediu cu mai multe fire de
execuție

using System;

public sealed class PrinterSingleton


{
private static PrinterSingleton _instance;

private PrinterSingleton() { }

public static PrinterSingleton GetInstance()


{
if (_instance == null)
{
_instance = new PrinterSingleton();
}
return _instance;
}

public void PrintDocument(string document)


{
Console.WriteLine("Printing document: " + document);
}
}

class Program
{
static void Main(string[] args)
{
PrinterSingleton printer = PrinterSingleton.GetInstance();

// Utilizatori care tipăresc documente


printer.PrintDocument("Document A");
printer.PrintDocument("Document B");
printer.PrintDocument("Document C");
}
}

2. Thread-safe Singleton: O soluție care rezolvă problema


implementării Naïve Singleton în medii cu mai multe fire de
execuție.

using System;
using System.Threading;

public sealed class ThreadSafePrinterSingleton


{
private static ThreadSafePrinterSingleton _instance;
private static readonly object LockObject = new object();

private ThreadSafePrinterSingleton() { }

public static ThreadSafePrinterSingleton GetInstance()


{
lock (LockObject)
{
if (_instance == null)
{
_instance = new ThreadSafePrinterSingleton();
}
}
return _instance;
}

public void PrintDocument(string document)


{
Console.WriteLine("Printing document: " + document);
}
}

class Program
{
static void Main(string[] args)
{
ThreadSafePrinterSingleton printer =
ThreadSafePrinterSingleton.GetInstance();

// Utilizatori care tipăresc documente în medii cu mai multe fire de execuție


Thread thread1 = new Thread(() => printer.PrintDocument("Document X"));
Thread thread2 = new Thread(() => printer.PrintDocument("Document Y"));

thread1.Start();
thread2.Start();

thread1.Join();
thread2.Join();
}
}

Avantaje și dezavantaje

Avantaje:
• Poți fi sigur că o clasă are doar o singură instanță.
• Obții un punct global de acces la acea instanță.
• Obiectul singleton este inițializat doar atunci când este
solicitat pentru prima dată.

Dezavantaje:
• Încalcă Principiul Responsabilității Unice, rezolvând două
probleme simultan.
• Poate masca un design prost, de exemplu, când
componentele programului știu prea multe una despre
cealaltă.
• Necesită tratament special într-un mediu cu mai multe fire
de execuție pentru a evita crearea unui obiect singleton de
mai multe ori.
• Poate fi dificil să testezi unitar codul clientului Singleton
din cauza lipsei de posibilitate de a suprascrie metodele
statice în majoritatea limbajelor.
Bibiliografie

1. https://refactoring.guru/design-patterns/singleton
2. https://refactoring.guru/design-patterns/csharp

S-ar putea să vă placă și