Ze wzorcami projektowymi bywa różnie. Niektóre są bardzo przydatne, inne mniej, a jeszcze inne są pożądane tylko w określonych sytuacjach. Ogólnie bar

Ze wzorcami projektowymi bywa różnie. Niektóre są bardzo przydatne, inne mniej, a jeszcze inne są pożądane tylko w określonych sytuacjach. Ogólnie bardzo łatwo wpaść w pułapkę nadużycia określonych rozwiązań. Taka sytuacja ma często miejsce w przypadku wzorca projektowego singleton. Singleton pozwala na stworzenie kodu klasy, która zawsze będzie miała jedną i tę samą instancję. Ogółem ten wzorzec ma więcej zalet — poniżej lista najważniejszych:

  • możliwość trzymania jednej instancji klasy per proces aplikacji,
  • łatwy dostęp do instancji,
  • możliwość przechowywania informacji lub stanu przez cały czas życia aplikacji,
  • łatwa implementacja mechanizmu lazy loading.

  Oczywiście nie ma rozwiązań idealnych, czego najlepszym przykładem jest właśnie singleton. Poniżej lista kilku istotnych wad:

  • instancja żyje przez cały czas życia aplikacji, co oznacza, że wykorzystywane przez nią zasoby zostaną zwolnione dopiero przy zamknięciu aplikacji;
  • bardzo trudno jest testować kod aplikacji, która wykorzystuje singletony;
  • występuje problem z użyciem IoC;
  • wzorzec jest bardzo uzależniający.

  W początkowej fazie zauroczenia tym wzorcem programiści często oddają mu się bez reszty i najchętniej tworzyliby aplikacje zbudowane tylko z singletonów, co samo w sobie jest beznadziejnym rozwiązaniem. Singleton w nadmiarze bowiem więcej szkodzi, niż pomaga.   Budowa klasy Zastosowanie wzorca singleton sprowadza się właściwie do przygotowania klasy, która ma odpowiednią budowę. Kluczowych jest kilka elementów:

  • dostęp do instancji za pomocą statycznej właściwości;
  • prywatny konstruktor, który blokuje tworzenie instancji na zewnątrz klasy;
  • tworzenie instancji na żądanie (lazy loading);
  • modyfikator sealed, który blokuje dziedziczenie z klasy singletonu.

  Poniżej przykładowa klasa, która spełnia wszystkie powyższe założenia: [sourcecode language="csharp"] public sealed class MySingleton { private static MySingleton _instance; // Statyczny kod zapewniający dostęp do instancji public static MySingleton Instance { get { if (_instance == null) { _instance = new MySingleton(); } return _instance; } } // Przykładowa metoda public void DoSomething() { Console.WriteLine($"Current value property TestProperty is: {TestProperty}."); } // Przykładowa właściwość public string TestProperty { get; set; } // Prywatny konstruktor blokuje tworzenie instancji na zewnątrz private MySingleton() { } } [/sourcecode]   Jak widać, poza specyficznym podejściem do tworzenia nowych obiektów MySingleton jest prawie zwykłym bytem. Przykładowe użycie (gdziekolwiek w kodzie całej aplikacji) jest bardzo proste: [sourcecode language="csharp"] MySingleton.Instance.TestProperty = "lalalala"; MySingleton.Instance.DoSomething(); [/sourcecode] Zgodnie z wcześniejszym listingiem, powyższe wywołanie utworzy instancję klasy MySingleton, a następnie wykona na niej obie operacje.   Singleton a IoC Singleton ma swoje wady i zalety i jak wszystko powinien być stosowany z rozwagą. W dzisiejszych czasach istnieje jednak poważna alternatywa dla tego rozwiązania, a jest nią IoC. O ile korzystamy z wystarczająco konfigurowalnego narzędzia (np. Autofac), możemy w łatwy sposób zdefiniować, jak ma być zarejestrowana określona klasa. W popularnym Autofacu wystarczy w tym celu zarejestrować dowolną klasę jako SingleInstance: [sourcecode language="csharp"] var builder = new ContainerBuilder(); builder.RegisterType<MyClass>().As<IMyInterface>().SingleInstance(); var container = builder.Build(); [/sourcecode]   Co zyskujemy dzięki takiemu rozwiązaniu? Właściwie wszystko to, co straciliśmy, stosując normalnego singletona:

  • możemy swobodnie korzystać z IoC;
  • kod wciąż da się łatwo przetestować;
  • w razie potrzeby klasę można zarejestrować do pracy w trybie innym niż SingleInstance.

Oczywiście sam kontener IoC jest pewnym narzutem — trzeba go wybrać, zainstalować i skonfigurować. Jeśli mamy prostą i małą aplikację, może on być zbędnym dodatkiem. Dlatego też, o czym już wspominałem, wszystkiego powinniśmy używać z rozwagą!  

Jerzy Piechowiak

Altcontroldelete.pl

 


 

 Szukasz informacji o C#? Kliknij TU lub zerknij poniżej: