Czy niezmienne / bezpaństwowe singletony są złe?

12

Ostatnio nastąpiła jakaś rewolucja przeciwko singletonom, ale czy jest coś z nimi nie tak, jeśli są bezpaństwowcami?

Wiem, że mowa o nadużywaniu i wszystko ... dotyczy to wszystkiego, nie tylko singli.

m3th0dman
źródło
1
Nie. Singletony w zasadzie nie są złe, są po prostu masowo nadużywane.
Bart van Ingen Schenau
3
co masz na myśli ostatnio?
Manoj R
5
@Jachach Sauer: Dlaczego miałbyś wymieniać; jeśli jest bezpaństwowiec, możesz go przetestować bezpośrednio.
m3th0dman
1
Jeśli masz bezpaństwowego singletona, to w zasadzie masz statyczną klasę użyteczności, która ma tendencję do stania się anty-wzorem Boskiej klasy. Zwykle możesz użyć metod statycznych zamiast w kontekście, w którym są używane (lub nawet lepiej: użyj metod rozszerzenia w C #).
Spoike
1
Możliwy duplikat Singletona bez żadnego stanu
Caleth

Odpowiedzi:

12
  > Are immutable/stateless singletons bad?
  • Nie, jeśli nie zależą od innych systemów zewnętrznych.
    • Przykład: Stringutility, który ucieka HTML w ciągu.
    • Powód: w unittests nie ma potrzeby zastępowania tego przez próbę / symulator.
  • Tak, jeśli twój niezmienny / bezpaństwowy singleton zależy od innych zewnętrznych systemów / usług i jeśli chcesz przeprowadzić testowanie (testowanie w izolacji)
    • Przykład: usługa zależna od zewnętrznej usługi kalkulatora podatkowego.
    • Powód: W celu przeprowadzenia unittests z tą usługą (w izolacji) musisz symulować / wyśmiewać zewnętrzne systemy / usługi.

Aby uzyskać więcej informacji, zobacz architekturę cebuli


  • Singleton-s może sprawić, że testy jednostkowe (w izolacji) będą trudniejsze / niemożliwe i
  • ukryte zależności / sprzężenie może być postrzegane jako problem, zgodnie z wyjaśnieniem @yBee

Nie widzę innych powodów, dla których nie używam Singletonów.

k3b
źródło
Nadal będziesz musiał kpić z zewnętrznej usługi internetowej, jeśli chcesz przetestować swoją klasę, nawet jeśli nie jest to singleton (bezstanowy).
m3th0dman
@ m3th0dman Zgadzam się
k3b
10

Zawsze zależy od użytkowania. Myślę, że rewolucja pochodzi z faktu, że każdy programista uczy ten wzór jako na wzór obiektowego. Większość zapomina pomyśleć o tym, gdzie ma to sens, a gdzie nie.
Dotyczy to oczywiście każdego wzoru. Używając wzorów nie tworzysz dobrego kodu ani dobrego oprogramowania.

Jeśli masz singletona bezstanowego, dlaczego nie użyć klasy oferującej tylko metody statyczne (lub użyć klasy statycznej)?

Oto kilka postów dotyczących zmiennych globalnych i ogólnie singletonów.

Nie byłbym tak surowy jak autor, ale pokazuje, że w większości przypadków, w których uważasz, że potrzebujesz singletonu, tak naprawdę go nie potrzebujesz.

StampedeXV
źródło
1
Dlaczego nie użyć klasy z metodami statycznymi? Dziedziczenie na przykład ...
m3th0dman
3
@ m3th0dman: Nie brzmi jak dobre miejsce do dziedziczenia.
Billy ONeal
@BillyONeal Możesz powiedzieć, że coś jest dobre lub złe dla dziedziczenia, jeśli znasz model domeny, co należy modelować w ten sposób ...
m3th0dman
2
@ m3th0dman: Erm, no. Mogę być całkiem pozytywny, nie wiedząc nic o modelu domeny. Dziedziczenie dotyczy zachowania polimorficznego. Ale jako singleton nie będziesz zachowywał się polimorficznie.
Billy ONeal
1
@ m3th0dman: Ponieważ uzyskanie obiektu singleton wymaga podania nazwy singletonu w witrynie wywołującej. Co oznacza, że ​​nie używasz zachowania polimorficznego. Co oznacza, że ​​kompozycja jest znacznie bardziej elastyczna niż dziedziczenie.
Billy ONeal
7

Nic nie może zrobić niezmienny bezpaństwowy singleton, czego nie zrobi klasa statyczna.

Po prostu nie ma powodu, aby dodawać dodatkowy poziom złożoności, który powoduje -> Instancja (), podczas gdy zwykłe wywołanie metody statycznej będzie wyraźniejsze, bardziej konserwatywne pod względem zasobów i prawdopodobnie szybsze.

Nie chodzi o to, że się mylą. Jest na to lepszy sposób. Istnieją scenariusze, w których normalne („stanowe”) singletony są właściwą drogą. Zło związane z singletonem polega na tym, że są one często wykorzystywane, z takimi samymi złymi wynikami jak zmienne globalne, ale istnieją szczególne przypadki, w których użycie singletonu jest po prostu prawidłowe. Nie ma takich przypadków dla bezpaństwowców.

SF.
źródło
Założę się, że możesz skonstruować kilka przypadków, w których Singleton ma pewne zalety. W zależności od scenariusza i ewentualnie języka programowania (np. Korzystając z leniwego ładowania).
StampedeXV
1
@StampedeXV: Tak, z pewnością stanowy singleton. Bezpaństwowy i niezmienny - byłbym naprawdę ciekawy usłyszeć jakieś przykłady, ale nie wstrzymuję oddechu.
SF.
Ok, masz rację. Uogólniłem trochę twoją odpowiedź. Dla niezmiennych bezpaństwowców też nie widzę żadnej przewagi.
StampedeXV
1
W przypadku klas, które mają tylko funkcje statyczne, nie można używać dziedziczenia / polimorfizmu, co jest dużym ograniczeniem ...
m3th0dman
1
Nic nie może zrobić niezmienny bezpaństwowy singleton, czego nie zrobi klasa statyczna. cóż, metody statyczne nie mogą zaimplementować interfejsu, który mógłby singleton
Michał M
3

Główny problem związany z singletonem polega na tym, że ukrywa on zależności i sprzężenie, szczególnie gdy jest stosowany w scenariuszu problemów przekrojowych. Zobacz Singletony są patologicznymi kłamcami lub dlaczego Singletony są złe do dalszego czytania.

Z drugiej strony stan mniej singleton, jeśli nie jest nadużywany, może być pomocny i poprawić wydajność. Rozważ przykład:

interface Interface
{
    void Method();
}

class StatelessSingleton : Interface
{
    public static readonly StatelessSingleton Instance = new StatelessSingleton();
    private StatelessSingleton() { }

    public void Method() { }
}

class User
{
    public User(Interface i) { /* ... */ }
}

Tutaj StatelessSingleton działa jako domyślna implementacja interfejsu i jest wprowadzana do konstruktora użytkownika. Nie ma zakodowanych na stałe zależności i ukrytych zależności. Nie możemy użyć klasy statycznej ze względu na podstawowy interfejs, ale nie ma powodu, aby tworzyć więcej niż jedną instancję wartości domyślnej. Dlatego bezpaństwowy singleton wydaje się właściwym wyborem.

Może jednak powinniśmy użyć innego wzorca dla domyślnej implementacji:

class Implementation : Interface
{
    private readonly Action _method;

    public Implementation()
    {
        _method = new Action(() => { /* default */ });
    }

    public Implementation(Action custom)
    {
        _method = custom;
    }

    public void Method()
    {
        _method();
    }
}

Uderza w wydajność w stosunku do StatelessSingleton, ale stanowi ogólną implementację interfejsu. Podobne rozwiązanie stosuje interfejs IProgress .

Mimo to, po co pozwalać tworzyć więcej niż jedną implementację domyślnego zachowania? Jednak możemy połączyć dwa:

class Implementation : Interface
{
    public readonly Implementation Default = new Implementation();

    private readonly Action _method;

    private Implementation()
    {
        _method = new Action(() => { /* default */ });
    }

    public Implementation(Action custom)
    {
        _method = custom;
    }

    public void Method()
    {
        _method();
    }
}

Podsumowując, uważam, że istnieją miejsca (jak pokazano domyślnie), w których Singletony są przydatne. Główna definicja Singleton stwierdza, że ​​nie zezwala na tworzenie więcej niż jednej instancji klasy. To jak energia jądrowa. Może wytworzyć energię lub bombę. To zależy od człowieka.

yBee
źródło