2011-09-07 19 views
12

Powiedzmy, że mam program, który ma dużą liczbę opcji konfiguracyjnych. Użytkownik może określić je w pliku konfiguracyjnym. Mój program może analizować ten plik konfiguracyjny, ale w jaki sposób powinien on wewnętrznie przechowywać i przekazywać opcje?Jak zaprojektować program z wieloma opcjami konfiguracji?

W moim przypadku oprogramowanie służy do przeprowadzenia symulacji naukowej. Istnieje około 200 opcji, z których większość ma normalne wartości domyślne. Zazwyczaj użytkownik musi podać tylko około tuzina. Trudność, jaką napotykam, polega na tym, jak zaprojektować swój wewnętrzny kod. Wiele obiektów, które trzeba skonstruować, zależy od wielu opcji konfiguracyjnych. Na przykład obiekt może wymagać kilku ścieżek (dla miejsca, w którym będą przechowywane dane), niektórych opcji, które należy przekazać do algorytmów, które obiekt wywoła, oraz niektórych opcji, które są używane bezpośrednio przez sam obiekt.

Prowadzi to do obiektów wymagających bardzo dużej liczby argumentów do skonstruowania. Dodatkowo, ponieważ moja baza kodów jest bardzo aktywnie rozwijana, bardzo trudno jest przejść przez stos wywołań i przekazać nową opcję konfiguracji, aż do miejsca, w którym jest potrzebna.

Jednym ze sposobów uniknięcia tego bólu jest posiadanie obiektu konfiguracji globalnej, który można swobodnie używać w dowolnym miejscu kodu. Nie podoba mi się to podejście, ponieważ prowadzi do funkcji i klas, które nie przyjmują żadnego (lub tylko jednego) argumentu i nie jest oczywiste dla czytelnika, z jakimi danymi korzysta dana funkcja/klasa. Zapobiega także ponownemu użyciu kodu, ponieważ cały kod zależy od gigantycznego obiektu konfiguracyjnego.

Czy ktoś może udzielić mi porady dotyczącej tego, jak powinien wyglądać taki program?

Oto przykład tego, co oznacza dla konfiguracji opcja mijania stylu:

class A: 
    def __init__(self, opt_a, opt_b, ..., opt_z): 
     self.opt_a = opt_a 
     self.opt_b = opt_b 
     ... 
     self.opt_z = opt_z 

    def foo(self, arg): 
     algo(arg, opt_a, opt_e) 

Oto przykład globalnego stylu config:

class A: 
    def __init__(self, config): 
     self.config = config 

    def foo(self, arg): 
     algo(arg, config) 

Przykłady są w Pythonie, ale moja pytanie oznacza wszelkie podobne języki programowania.

+0

Globalny obiekt konfiguracyjny łączy wszystkie kody razem. Byłoby miło, gdyby program był bardziej modułowy. Podoba mi się rozwiązanie pokazane przez @HYRY. Wygląda jak najlepszy z obu światów. – qsc

Odpowiedz

5

matplotlib jest duży pakiet z wielu opcji konfiguracyjnych. Używa modułu rcParams do zarządzania wszystkimi domyślnymi parametrami. rcParams zapisz wszystkie domyślne parametry w dyktafonie.

Co funkcje dostanie opcje z argurments słów kluczowych:

na przykład:

def f(x,y,opt_a=None, opt_b=None): 
    if opt_a is None: opt_a = rcParams['group1.opt_a'] 
2

Kilka wzorce projektowe pomoże

  • Prototype
  • fabryczne i Abstract Factory

Za pomocą tych dwóch wzorów z obiektami konfiguracyjnych. Każda metoda pobierze obiekt konfiguracyjny i użyje tego, czego potrzebuje. Rozważ także zastosowanie grupowania logicznego do parametrów konfiguracyjnych i zastanów się nad sposobami zmniejszenia liczby wejść.

kod psuedo

// Consider we can run three different kinds of Simulations. sim1, sim2, sim3 

ConfigFactory configFactory = new ConfigFactory("/path/to/option/file"); 
.... 
Simulation1 sim1; 
Simulation2 sim2; 
Simulation3 sim3; 

sim1.run(configFactory.ConfigForSim1()); 
sim2.run(configFactory.ConfigForSim2()); 
sim3.run(configFactory.ConfigForSim3()); 

Wewnątrz każdej metody fabrycznej może utworzyć konfigurację z obiektu prototypowego (który ma wszystkie „rozsądnych” domyślne) oraz plik opcji staje się tylko te rzeczy, które są różne od domyślna. Będzie to połączone z jasną dokumentacją na temat tego, czym są te wartości domyślne i kiedy dana osoba (lub inny program) może chcieć je zmienić.

** Edycja: ** Należy również wziąć pod uwagę, że każda konfiguracja zwrócona przez producenta jest podzbiorem ogólnej konfiguracji.

2

Przekaż klasę parsowania konfiguracji lub napisz klasę, która ją zawija i inteligentnie wyciągnie żądane opcje.

Standardowa biblioteka Pythona configparser odsłania sekcje i opcje pliku konfiguracyjnego stylu INI za pomocą protokołu odwzorowania, dzięki czemu można pobierać opcje bezpośrednio z tego, jakby był słownikiem.

myconf = configparser.ConfigParser() 
myconf.read('myconf.ini') 
what_to_do = myconf['section']['option'] 

Jeśli wyraźnie chcą dostarczać opcje za pomocą notacji atrybutu, należy utworzyć klasę, która zasłania __getattr__:

class MyConf: 
    def __init__(self, path): 
     self._parser = configparser.ConfigParser() 
     self._parser.read('myconf.ini') 
    def __getattr__(self, option): 
     return self._parser[{'what_to_do': 'section'}[option]][option] 

myconf = MyConf() 
what_to_do = myconf.what_to_do 
0

mają ładowaniu modułu params jego nazw, a następnie zaimportować je i używać wszędzie tam, gdzie chcesz.
Zobacz także powiązane pytanie here

Powiązane problemy