Wilk w owczej skórze jest to - powiedziałby Yoda o wzorcu Singleton. Wzorzec ten jest nadużywany z powodu niezrozumienia tego właśnie faktu. Jeżeli tworzymy singletona to tak naprawdę nie powinniśmy chcieć żeby ktokolwiek o tym wiedział.
Kiedy raz stworzymy singletona możemy używać go jako instancji zwykłej klasy, przekazywać go między metodami i funkcjami jako zwykły obiekt a nawet tworzyć właściwości które będą przechowywać singletona w odległych częściach kodu, wcale o tym nie wiedząc.
Początkujący programiści nadużywają Singletona myśląc, że skoro "udostępnili" taki obiekt, to wszystkie odwołania z całego programu powinny dotyczyć tego właśnie jednego obiektu. Na przykład wszystkie zapytania z całego systemu powinny odwoływać się do jednego obiektu System.BazaDanych.Instancja.
Także traktowanie Singletona tylko jako nowoczesnej formy zmiennej globalnej to pomyłka.
To pogwałcenie paru dobrych praktyk programowania, a przede wszystkim złamanie najważniejszej. Najważniejsza brzmi, że żadna klasa nie powinna wiedzieć o tym, że używa Singletona.
W związku z tym klasa kliencka powinna dostawać Singletona w postaci parametru albo argumentu konstruktora i przechowywać sobie go jako zwykłą zmienną wewnątrz kodu. Dzięki temu drastycznie zmniejszamy liczbę referencji do właściwości Singletona a więc i ułatwiamy sobie późniejsze zmiany w kodzie.
Powiedzmy, że mamy 10 klas z których każda ma 10 metod, a każda używa połączenia z bazą danych. Oznacza to 100 odwołań do Singletona. A więc w przypadku zmiany np. typu Singletona musimy zmienić 100 klientów tej klasy. Jeżeli jednak do każdej klasy przekażemy Singletona jako zwykły parametr albo argument konstruktora, a każda klasa zajmie się zapisaniem we własnej właściwości tego Singletona, a każde odwołanie do niego będzie odbywać się przez wewnętrzną właściwość klasy to mamy już tylko 10 odwołań do Singletona.
Przykład:
public sealed class BazaDanych
{
static readonly BazaDanych instance=new BazaDanych();
public static BazaDanych Instance
{
get
{
return instance;
}
}
}
A teraz odwołania klientów do Singletona:
class WarstwaDanych
{
public List<object> PobierzKlientow()
{
return BazaDanych.Instance.Pobierz("SELECT NAME FROM CLIENTS");
}
public List<object> PobierzProdukty()
{
return BazaDanych.Instance.Pobierz("SELECT NAME FROM PRODUCTS");
}
}
I tak dalej. Jednak poprawnie powinno wyglądać tak:
class WarstwaDanych
{
BazaDanych Baza;
public WarstwaDanych(BazaDanych baza)
{
Baza = baza;
}
public List<object> PobierzKlientow()
{
return Baza.Pobierz("SELECT NAME FROM CLIENTS");
}
public List<object> PobierzProdukty()
{
return Baza.Pobierz("SELECT NAME FROM PRODUCTS");
}
}
Jest o wiele więcej przykładów jak używać poprawnie Singletona, jednak myślę, że ten pierwszy podstawowy zainteresuje Was na tyle, aby poświęcić więcej czasu na poznanie sposobów jego użycia nawet gdy nie jest on z budowy równie ekscytujący co dekoratory i fabryki ;)
Singleton jest chyba najprostszym do zrozumienia wzorcem jeżeli chodzi o wklepanie go. Jednak sposoby użycia i pożytki z niego płynące to szerszy temat i niestety nie zawsze ludzie w to wnikają. Dlatego czasem Singleton może budzić niedobre skojarzenia jeżeli jest używany niewłaściwie. A w rzeczywistości to bardzo pożyteczny, skryty i niedoceniony wzorzec.
Zaloguj się, aby dodać swoją odpowiedź