Singleton bezpieczny wątkowo
Część sekcji Programowanie obiektowe ścieżki C# w Coddy. Lekcja 52 z 70.
Wzorzec Singleton gwarantuje, że klasa ma tylko jedną instancję w całej aplikacji, i zapewnia globalny punkt dostępu do niej. Jest to przydatne do zarządzania współdzielonymi zasobami, takimi jak ustawienia konfiguracji, usługi rejestrowania zdarzeń czy połączenia z bazą danych.
Podstawowy wzorzec Singleton wykorzystuje prywatny konstruktor, aby uniemożliwić tworzenie instancji z zewnątrz, oraz właściwość statyczną, która zapewnia dostęp:
public class Logger
{
private static Logger _instance;
private static readonly object _lock = new object();
private Logger() { } // Prywatny konstruktor
public static Logger Instance
{
get
{
lock (_lock)
{
if (_instance == null)
_instance = new Logger();
return _instance;
}
}
}
public void Log(string message) => Console.WriteLine(message);
}Instrukcja lock zapewnia bezpieczeństwo wątkowe — jeśli wiele wątków próbuje jednocześnie uzyskać dostęp do Instance, tylko jeden może w danej chwili wejść do sekcji krytycznej. Bez tego dwa wątki mogłyby jednocześnie stwierdzić, że _instance ma wartość null, i utworzyć oddzielne instancje.
C# oferuje prostsze podejście bezpieczne wątkowo, wykorzystujące inicjalizację statyczną:
public class Logger
{
private static readonly Logger _instance = new Logger();
private Logger() { }
public static Logger Instance => _instance;
public void Log(string message) => Console.WriteLine(message);
}Ta wersja jest bezpieczna wątkowo, ponieważ środowisko CLR gwarantuje, że inicjalizacja pola statycznego odbywa się tylko raz. Oba podejścia zapewniają, że zawsze otrzymujesz tę samą instancję:
Logger.Instance.Log("First call");
Logger.Instance.Log("Same instance");Wyzwanie
ŁatwyStwórzmy bezpieczny wątkowo menedżer konfiguracji, korzystając ze wzorca Singleton. W rzeczywistych aplikacjach ustawienia konfiguracji muszą być dostępne w całym programie, a jednocześnie musi istnieć tylko jedna instancja — to idealne zastosowanie wzorca Singleton.
Rozmieścisz kod w dwóch plikach:
ConfigManager.cs: Utwórz klasęConfigManagerw przestrzeni nazwConfiguration, która implementuje wzorzec Singleton. Twój menedżer konfiguracji powinien:- Mieć prywatne pole statyczne przechowujące jedyną instancję
- Używać prywatnego konstruktora, aby uniemożliwić tworzenie instancji z zewnątrz
- Udostępniać statyczną właściwość
Instance, która zwraca jedyną instancję (użyj prostszego podejścia ze statyczną inicjalizacją, aby zapewnić bezpieczeństwo wątkowe) - Zawierać prywatne pole tekstowe
_appNamezainicjalizowane wartością"MyApp" - Mieć metodę
SetAppName(string name)do aktualizowania nazwy aplikacji - Mieć metodę
GetAppName(), która zwraca bieżącą nazwę aplikacji
Program.cs: W pliku głównym pokaż, że Singleton działa poprawnie, uzyskując dostęp do instancji wielokrotnie i demonstrując, że zmiany są widoczne we wszystkich odwołaniach.
Otrzymasz jedno wejście:
- Nowa nazwa aplikacji do ustawienia (np.
ProductionServer)
W programie:
- Pobierz instancję
ConfigManageri wypisz domyślną nazwę aplikacji - Pobierz instancję ponownie (do innej zmiennej) i użyj jej do ustawienia nowej nazwy aplikacji z wejścia
- Pobierz instancję po raz trzeci i wypisz nazwę aplikacji, aby udowodnić, że wszystkie odwołania współdzielą te same dane
Na przykład, jeśli wejściem jest ProductionServer, wynikiem powinno być:
MyApp
ProductionServerTo pokazuje główną zaletę wzorca Singleton — bez względu na to, ile razy uzyskasz dostęp do Instance, zawsze otrzymasz ten sam obiekt ze współdzielonym stanem. Podejście ze statyczną inicjalizacją gwarantuje bezpieczeństwo wątkowe, ponieważ CLR zapewnia, że pole statyczne zostanie zainicjalizowane tylko raz, nawet jeśli jednocześnie uzyska do niego dostęp wiele wątków.
Spróbuj swoich sił
using System;
using Configuration;
class Program
{
public static void Main(string[] args)
{
// Wczytaj dane wejściowe - nową nazwę aplikacji
string newAppName = Console.ReadLine();
// TODO: Pobierz instancję ConfigManager i wypisz domyślną nazwę aplikacji
// TODO: Pobierz instancję ponownie (do innej zmiennej) i użyj jej do ustawienia nowej nazwy aplikacji
// TODO: Pobierz instancję po raz trzeci i wypisz nazwę aplikacji, aby wykazać, że wszystkie odwołania współdzielą te same dane
}
}
Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.
Wszystkie lekcje w sekcji Programowanie obiektowe
1Podstawy programowania obiektowego
Pliki zewnętrznePrzestrzenie nazw i dyrektywyWprowadzenie do klas i obiektówSłowo kluczowe „this”Metody i parametryPola a właściwościKonstruktoryInicjalizatory obiektówPodsumowanie — prosty kalkulator4Dziedziczenie
Podstawowa składnia dziedziczenia (:)Słowo kluczowe 'base'Słowa kluczowe virtual i overrideKlasy sealedBazowa klasa 'object'Powtórzenie – hierarchia pracowników7Zaawansowane funkcje
Przeciążanie operatorówIndeksery (this[])Nadpisywanie ToString()Metody rozszerzającePodsumowanie – własna lista10Wzorce projektowe — część 1
Wprowadzenie do wzorców projektowychSingleton bezpieczny wątkowoWzorzec fabrykiWzorzec obserwatora (zdarzenia)Wzorzec strategii2Właściwości i składowe statyczne
Właściwości automatyczneWłaściwości tylko do odczytu i zapisuPola i metody statyczneKlasy statyczneSkładowe z ciałem wyrażeniowym5Polimorfizm i interfejsy
Polimorfizm czasu kompilacji a czasu wykonaniaInterfejs a klasa abstrakcyjnaWiele interfejsówJawne implementowanie interfejsówRzutowanie w górę i w dółPowtórka — kalkulator kształtów8Zaawansowane koncepcje OOP
Kompozycja zamiast dziedziczeniaTypy generyczne (klasy i metody)Delegaty i zdarzeniaAtrybuty i refleksjaIDisposable i instrukcja usingPodstawy wstrzykiwania zależności11Wzorce projektowe, część 2
Wzorzec poleceniaWzorzec adapteraWzorzec dekoratoraWzorzec metody szablonowejWzorzec stanuWzorzec kompozytu3Architektura klas
Dane instancji a dane statyczneSłowa kluczowe 'readonly' i 'const'Pola zapasowePowtórzenie — menedżer kont bankowych6Hermetyzacja
Modyfikatory dostępuWłaściwości w hermetyzacjiImplementacja ukrywania danychWzorce niezmiennościPowtórka — dane studentów9Argumenty zmiennej liczby
Słowo kluczowe „params”Parametry opcjonalneArgumenty nazwanePrzeciążanie metodPoćwicz samodzielnie: Kompilator C# online