Kolejnym wzorcem projektowym, który omówię jest Singleton. Jest to jeden z najprostszych wzorców projektowych, ale i jedyny który ma tak wiele różnych implementacji.
Wzorzec ten pozwala na tworzenie tylko jednego obiektu. Spytasz po co mi tylko jeden obiekt danej klasy? Przydaje się to w wielu miejscach aplikacji. Przykładowo kilka zastosowań to: ustawienia aplikacji, dostęp do pliku (zapis), tworzenie logów.
Zapewne może się wydawać, że tworzenie specjalnego wzorca dla tego typu zastosować jest nieopłacalne. Ktoś może powiedzieć: skoro mamy utworzyć jeden obiekt to zróbmy jedną zmienną globalną i bez cyrków mamy to co nam potrzeba. Jest jednak jeden minus tego rozwiązania. Jeśli tworzymy zmienną globalną to utworzyć musimy ją przy starcie naszej aplikacji a jeśli nasza aplikacja działa bardzo długo to tym gorzej dla nas - marnujemy cenne zasoby. Singleton pozwala na utworzenie siebie tylko wtedy kiedy jest na prawdę potrzebny.
Spójrzmy na diagram UML:
Jak widać mamy tu do czynienia z jedną klasą Singleton. Konstruktor klasy jest prywatny, dzięki czemu zapobiegamy tworzeniu obiektów tej klasy. Pole instance przechowuje utworzony obiekt Singletonu a metoda GetInstance tworzy lub zwraca już istniejący obiekt Singletona.Zobaczmy na przykładową implementację tego wzorca:
1 class Singleton
2 {
3 private static Singleton _instance;
4 public int i;
5 private Singleton()
6 {
7 }
8
9 public static Singleton GetInstance()
10 {
11 return _instance == null ? (_instance = new Singleton()) : _instance;
12 }
13 }
14
15 class Program
16 {
17 static void Main(string[] args)
18 {
19 Singleton sing = Singleton.GetInstance();
20 sing.i = 20;
21 Console.WriteLine(sing.i);
22 Singleton s = Singleton.GetInstance();
23 Console.WriteLine(sing.i);
24 }
25 }
Implementacja wydaje mi się bardzo prosta w zrozumieniu. W klasie mamy statyczne pole _instance i metodę GetInstance(), która w zależności od tego czy jeszcze nie utworzono obiektu czy też utworzono zwraca odpowiednią wartość.
Kod przedstawiony powyżej, pomimo swojej prostoty, może sprawić nam nie lada problem w aplikacjach wielowątkowych. Podczas gdy nasz kod wykorzystywałby wiele wątków, mogło by dojść do sytuacji kiedy każdy wątek w tej samej chwili spróbowałby utworzyć instancję Singletonu - a wtedy katastrofa murowana. Najprostszym rozwiązaniem jest zastosowanie tworzenia obiektu w deklaracji:
1 class Singleton
2 {
3 private static readonly Singleton _instance = new Singleton();
4 public int i;
5 private Singleton()
6 {
7 }
8
9 public static Singleton GetInstance()
10 {
11 return _instance;
12 }
13 }
Framework .NET gwarantuje w takim przypadku, że pole jest thread safe. W dokumentacji na MSDN można znaleźć wiele takich adnotacji do istniejących klas w .NET.
Inną opcją jest tzw. podwójne sprawdzanie. Jednak podana wyżej metoda jest prostsza i szybsza w implementacji.
Wiele innych metod implementacji Singletonu można znaleźć na wielu internetowych stronach. Polecam zaznajomić się z innymi możliwymi konstrukcjami.
Brak komentarzy:
Prześlij komentarz