2010-07-03 14 views
7

Jestem programistą internetowym od jakiegoś czasu przy użyciu ASP.NET i C#, chcę spróbować i zwiększyć swoje umiejętności za pomocą najlepszych praktyk.Alternatywy dla wzoru singleton?

Mam stronę internetową. Chcę załadować ustawienia jednorazowo i odsyłać je tam, gdzie jest to potrzebne. Zrobiłem więc pewne badania i 50% programistów wydaje się używać tego wzorca singleton. A pozostałe 50% programistów to mrówki-singletony. Wszyscy nienawidzą singletonów. Zalecają wstrzyknięcie zależności.

Dlaczego single są złe? Jaką dobrą praktyką jest ładowanie ustawień stron internetowych? Czy powinny być ładowane tylko raz i tam gdzie jest to potrzebne? Jak mam to zrobić z zastrzykiem zależności (jestem na tym nowym)? Czy są jakieś próbki, które ktoś mógłby polecić dla mojego scenariusza? Chciałbym także zobaczyć kod testowy jednostki dla tego (dla mojego scenariusza).

Dzięki Brendan

+0

możliwy duplikat [Czy istnieją realne alternatywy dla wzoru Singleton GOF?] (Http://stackoverflow.com/questions/162042/are-there-any-viable-alternatives-to-the-gof-singleton- wzór) –

Odpowiedz

6

Generalnie unikam singletonów, ponieważ utrudniają one testowanie aplikacji. Singletony są trudne do podrobienia w testach jednostkowych właśnie ze względu na ich naturę - zawsze otrzymujesz ten sam, a nie taki, który możesz łatwo skonfigurować do testu jednostkowego. Dane konfiguracyjne - mimo wszystko mocno wpisane dane konfiguracyjne - jest jednak jednym wyjątkiem. Zazwyczaj dane konfiguracyjne są względnie statyczne, a alternatywą jest pisanie sporej ilości kodu w celu uniknięcia klas statycznych, które framework zapewnia dostęp do pliku web.config.

Istnieje kilka różnych sposobów korzystania z niego, które pozwolą Ci jeszcze przetestować Twoją aplikację. Jednym ze sposobów (być może w obie strony, jeśli twój singleton nie leniwie czyta app.cofnig) jest posiadanie domyślnego pliku app.config w twoim projekcie testowym jednostki, dostarczającym wartości domyślnych wymaganych dla twoich testów. Możesz użyć odbicia, aby zastąpić określone wartości w miarę potrzeb w testach jednostkowych. Zazwyczaj skonfigurowałem prywatną metodę, która pozwala usunąć prywatną instancję singleton w konfiguracji testowej, jeśli wprowadzę zmiany dla poszczególnych testów.

Innym sposobem jest nie używanie bezpośrednio singletonu, ale stworzenie dla niego interfejsu, który implementuje klasa singleton. Możesz użyć ręcznego wtrysku interfejsu, domyślnie do instancji singleton, jeśli podana wartość jest pusta. Pozwala to utworzyć fałszywą instancję, którą można przekazać do testowanej klasy dla testów, ale w swoim rzeczywistym kodzie użyj instancji singleton. Zasadniczo każda klasa, która tego potrzebuje, zachowuje prywatne odwołanie do instancji singleton i używa jej. Podoba mi się trochę lepiej, ale ponieważ singleton zostanie utworzony, nadal może być potrzebny domyślny plik app.config, chyba że wszystkie wartości są leniwie załadowane.

public class Foo 
{ 
    private IAppConfiguration Configuration { get; set; } 

    public Foo() : this(null) { } 

    public Foo(IAppConfiguration config) 
    { 
     this.Configuration = config ?? AppConfiguration.Instance; 
    } 

    public void Bar() 
    { 
     var value = this.Config.SomeMaximum; 
     ... 
    } 
}  
+0

Przepraszam za późno. ciekawe uwagi na temat danych konfiguracyjnych jako wyjątku. Zazwyczaj stosuję odwrotne podejście. Próbuję implementować konfigurację środowiska wykonawczego jako interfejsy i wprowadzać je do aplikacji podczas uruchamiania. W ten sposób mój program zależy tylko od samych interfejsów, które można dowolnie zmieniać lub kpić z nich podczas testów. Podczas uruchamiania muszę czytać obiekty przy użyciu menedżera konfiguracji ConfigurationManager, ale jest to jedyne miejsce, które jest świadome tej klasy statycznej. – user734929

+0

Jest to podejście, do którego również przeszedłem, chociaż mój interfejs konfiguracyjny jest zarejestrowany jako singleton w moim kontenerze DI dla najlepszego z obu światów. Wciąż jest to jedyny przykład wdrożenia Singleton, w którym czuję się komfortowo. – tvanfosson

1

Jest spora dyskusja pojedynczych wzorów i kodowania przykłady tutaj ... http://en.wikipedia.org/wiki/Singleton_pattern Zobacz również tutaj ... http://en.wikipedia.org/wiki/Dependency_injection

Z jakiegoś powodu wydaje się podzielić singletons programistów pod silnym pro - i anty-obozy. Bez względu na zalety tego podejścia, jeśli twoi koledzy są przeciwko niemu, prawdopodobnie najlepiej go nie używać. Jeśli jesteś sam, spróbuj i zobacz.

+0

Chcę również przetestować to urządzenie, ale nie mam pojęcia jak przetestować singletowy wzór? –

1

Wzorce projektowe mogą być niesamowitymi rzeczami. Niestety, singleton wydaje się wystawać jak bolesny kciuk iw wielu przypadkach może być uważany za anty-wzór (promuje złe praktyki). Co dziwne, większość programistów zna tylko jeden wzorzec projektu, a jest to singleton.

Najlepiej byłoby, gdyby twoje ustawienia były zmienną składową w lokalizacji wysokiego poziomu, na przykład obiekt aplikacji będący właścicielem stron, które spawujesz. Strony mogą następnie poprosić aplikację o ustawienia lub aplikacja może przekazać ustawienia podczas tworzenia stron.

+0

W kursie wzornictwa projektowego, w którym brałem udział, singleton był pierwszym nauczanym. To może być powód, dla którego wszyscy to pamiętają. –

+3

@Brian: ten wzór jest opisany na stronie http://sites.google.com/site/steveyegge2/singleton-considered-stupid – wRAR

+0

Czy masz próbkę kodu opisaną przez Ciebie? Lub link? –

0

Jednym ze sposobów rozwiązania tego problemu jest odrzucenie go jako problemu z DAL .

Bez względu na to, jaka klasa/strona internetowa itp. Musi korzystać z ustawień konfiguracyjnych, należy zadeklarować zależność od usługi IConfigSettingsService (fabryka/repozytorium/cokolwiek-lubisz-je-zadzwonić-im).

private IConfigSettingsService _configSettingsService; 

public WebPage(IConfigSettingsService configSettingsService) 
{ 
    _configSettingsService = configSettingsService; 
} 

Więc twoja klasa dostanie ustawienia tak:

ConfigSettings _configSettings = _configSettingsService.GetTheOnlySettings(); 

realizacja ConfigSettingsService miałoby zależność, która jest klasa Dal. W jaki sposób Dal będzie wypełniać obiekt ConfigSettings? Kogo to obchodzi.

  • Może byłoby zapełnić ConfigSettings z pliku xml bazy danych lub .config, za każdym razem.

  • Może to zrobić za pierwszym razem, ale następnie wypełnić statyczne _configSettings dla kolejnych wywołań.

  • Może dostanie ustawienia z Redis. Jeśli coś wskazuje, że ustawienia się zmieniły, dal lub coś zewnętrznego może zaktualizować Redis. (Takie podejście będzie przydatna, jeśli masz więcej niż jedną aplikację, korzystając z ustawień.

Cokolwiek robi, to jedyna zależność jest non-Singleton interfejs usługi. To jest bardzo łatwe do makiety. W swoich badaniach ty może spowodować, że zwróci konfigurację ConfigSettings z dowolną zawartością).

W rzeczywistości najprawdopodobniej będzie to usługa MyPageBase, która ma zależność IConfigSettingsService, ale równie dobrze może być usługą sieciową, usługą systemu Windows, MVC somewhatsit lub wszystkimi powyższymi.