Config Class / Struct: Pattern czy Anti-Pattern? Alternatywy?


10

Jeśli dodasz nowe opcje konfiguracji do programu, może on często wywoływać mnóstwo efektów falowania, jeśli chodzi o uzyskanie opcji tam, gdzie trzeba działać. Istnieją trzy podstawowe sposoby radzenia sobie z tym, o których jestem świadomy:

  1. Przekaż wszystkie ustawienia konfiguracji do części programu, które potrzebują ich jawnie jako prymitywów. Jest to najbardziej wyraźny sposób, który najbardziej oddziela rzeczy. Minusem jest to, że jest to zarówno pełne, jak i kruche.

  2. Ustaw najczęściej używane ustawienia konfiguracji na globalne / statyczne. Jest to najprostszy sposób, ale wprowadza działanie na odległość, utrudnia testowanie i zakłada, że ​​konfiguracja naprawdę jest globalna (że w danym momencie chcesz mieć tylko jedną konfigurację).

  3. Utwórz klasę / strukturę konfiguracji, która zawiera wszystkie opcje konfiguracji dla całego programu lub każdego ważnego problemu w programie, a następnie przekaż to jawnie. Jest to mniej wyraźne niż (1), ale bardziej wyraźne niż (2). Jeśli chcesz zmienić ustawienie tylko dla jednego wywołania funkcji, możesz sklonować obiekt config i zmienić tę jedną wartość. Jest to przydatne zarówno w testowaniu, jak iw praktyce. Jednak nadal możesz potencjalnie przekazać tony informacji do funkcji, której nie potrzebuje, a zmiana wartości w klasie config / struct może nadal powodować działania na odległość.

Czy rozważyć (3) wzór lub anty-wzór? Jeśli to jest anty-wzór, co zamiast tego robisz?


Co powiesz na odmianę 3 - posiadanie kilku klas konfiguracji, przekazywanie odpowiedniej klasy tam, gdzie jest potrzebne?
Oded

@Oded: Chciałem podkreślić to jako możliwość. Edytowane.
dsimcha

Odpowiedzi:


4

Najlepszym rozwiązaniem byłoby zrobić kilka interfejsów konfiguracyjnych i wdrożyć je jak chcesz. Ogranicza to dostępność i utrzymuje lokalizację. Jednak o wiele za dużo wysiłku, aby być tego wartym, wystarczy po prostu zrzucić całą konfigurację w jednej klasie i przejść do problemu z dużo większą ilością grawitacji. To jest konfiguracja, a nie UtterlyCrucialAlwaysChangingClass - właściwie pozostanie taka sama. Dopóki nie uczynisz tego globalnym, a implementacja jest spójna, nie martwię się o to.


4
+1 za powiedzenie, że coś nie jest teoretycznie idealnym projektem, ale nadal może być dobre w praktyce, gdy weźmie się pod uwagę prostotę i prawdopodobieństwo zmiany (lub jej brak).
dsimcha

Właśnie wyrzuciłem cztery argumenty i zastąpiłem je klasą Settings. To wydawało się słuszne.
Martin Ueding

Nie rozumiem, którą z 3 opcji jesteś zwolennikiem. Czy możesz podać
DBedrenko,

1

Wolę opcję 1, ponieważ odsprzęganie umożliwia łatwiejsze testowanie, a ustawienia konfiguracji, od których zależy obiekt, są jawne. Jeśli obiekt wymaga ustawienia konfiguracji, wówczas jawnie podaj go do obiektu za pomocą argumentu konstruktora lub metody ustawiającej. Zmniejsz poziom szczegółowości za pomocą struktury wstrzykiwania zależności, aby wstrzyknąć te ustawienia konfiguracji do obiektu.


Sprzeciwiłeś się sobie: mówisz, że chcesz użyć Opcji 1, ale potem mów „Zmniejsz gadatliwość, używając struktury wstrzykiwania zależności, aby wstrzyknąć te ustawienia konfiguracji do obiektu”. czyli opcja 3: wstrzyknięcie konstruktora
DBedrenko,

0

Wyobraź sobie, że plik konfiguracyjny został napisany w formacie XML. Następnie możesz po prostu przekazać fragmenty tego kodu XML do każdego ze składników, aby uzyskać ich dane konfiguracyjne.

Jeśli używasz platformy .NET, możesz tworzyć klasy za pomocą DataContracts, których możesz używać XmlSerialiser do tworzenia hierarchii obiektów z konfiguracji Xml i przekazywać te obiekty jako konfigurację.

To wprowadza cię do następnego problemu. Twoje dane konfiguracyjne składają się z trzech różnych części. Strukturalna konfiguracja aplikacji, która organizuje biblioteki kodów, aby zachowywały się jak ten konkretny produkt. Ustawienia konfiguracji witryny zawierające ustawienia specyficzne dla instalacji oraz dane preferencji / ustawień użytkownika, które różnią się w zależności od użytkownika w systemie.

Wiedząc, która część jest która, i zachowując te ustawienia danych osobno, instalowanie aktualizacji będzie znacznie prostsze (bez utraty ustawień klientów)


0

Ustawiłbym klasę w opcji nr 3 na statyczną. Więc zamiast

//create SomeCl
Foo f = new Foo();
f.setConfigInst(cfg);
...
...
//Inside Foo
public void setConfig(MyAppConfig c) { localCfg = c; }
...
//somewhere else:
x = localCfg.getConfigForX();

Możesz po prostu mieć:

//Inside Foo
x = MyAppConfig.getConfigForX();

Niech szczegóły ładowania / zapisywania danych konfiguracyjnych pojawią się wewnątrz MyAppConfigklasy. I oczywiście możesz mieć bardziej złożone odmiany, takie jak różne klasy do różnych celów.

Jedynym przypadkiem, w którym takie podejście byłoby problemem, byłoby z jakiegoś powodu, aby pracować z wieloma instancjami różnych konfiguracji jednocześnie , chociaż jeszcze nie spotkałem się z taką sytuacją.


1
Tak właśnie dzieje się podczas uruchamiania testów jednostkowych w niektórych środowiskach testowych ... Ale nawet bez jednoznacznych równoległych testów jednostkowych będzie to utrudniać jednostkowe testowanie obiektów, które zależą od stanu globalnego.
Péter Török

0

Pracuję nad projektem, w którym wykorzystujemy podejście „3 warstwy (interfejs, logika biznesowa, dostęp do danych)”. Aplikacja może być serwerem WWW dla wielu użytkowników lub serwerem klienta.

Pracujemy w 3 różnych konfiguracjach, pierwszej specyficznej dla komputera PC, w której pracuje użytkownik. Drugi specyficzny dla bieżącego użytkownika i trzecia globalna konfiguracja dla wszystkich użytkowników i aplikacji klienckich.

Każda konfiguracja jest reprezentowana w każdym wystąpieniu aplikacji przez obiekt.

Takie podejście może pomóc w twoim projekcie.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.