2011-09-07 13 views
12

可以說我有一個程序,有大量的配置選項。用戶可以在配置文件中指定它們。我的程序可以解析這個配置文件,但它應該如何內部存儲和傳遞選項?如何設計具有多種配置選項的程序?

在我的情況下,該軟件用於執行科學模擬。大約有200個選項,其中大部分都有理智的默認設置。通常用戶只需指定十幾個。我面臨的困難是如何設計我的內部代碼。許多需要構建的對象取決於許多配置選項。例如,對象可能需要多個路徑(用於存儲數據的位置),某些選項需要傳遞給該對象將調用的算法,以及一些由對象本身直接使用的選項。

這會導致需要構建大量參數的對象。此外,由於我的代碼庫處於非常活躍的開發階段,因此通過調用堆棧並將新的配置選項一直傳遞到需要的地方是一件非常痛苦的事情。

防止這種痛苦的一種方法是擁有一個全局配置對象,可以在代碼的任何地方自由使用。我不特別喜歡這種方法,因爲它會導致函數和類不會採用任何(或只有一個)參數,讀者不明白函數/類處理的是什麼數據。它還防止代碼重用,因爲所有的代碼都依賴於巨大的配置對象。

任何人都可以給我一些關於如何構建這樣的程序的建議嗎?

這裏是我的意思的配置選項傳遞風格的例子:

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) 

下面是全局配置風格的例子:

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

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

的例子是在Python,但我問題代表任何類似的編程語言。

+0

全局配置對象將所有代碼連接在一起。讓程序更加模塊化將會很好。我喜歡@HYRY顯示的解決方案。這似乎是兩全其美。 – qsc

回答

5

matplotlib是一個大包與許多配置選項。它使用rcParams模塊來管理所有的默認參數。 rcParams將所有默認參數保存在字典中。

每個功能將獲得選擇從關鍵字argurments:

例如:

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

一些設計模式,將有助於

  • 原型
  • 工廠和抽象工廠

使用這兩種模式與配置對象。然後每個方法都會接受一個配置對象並使用它所需要的。還要考慮將邏輯分組應用於配置參數,並考慮減少輸入數量的方法。

僞代碼

// 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()); 

裏面,這也許可以從一個原型對象的配置(即具有所有的「健全的」缺省)和選項文件中的每個工廠方法變得只是從不同的東西默認。這將與關於這些默認值是什麼以及某人(或其他程序)何時需要更改它們的明確文檔配對。

**編輯:** 還要考慮工廠返回的每個配置都是整體配置的子集。

2

傳遞配置解析類,或者編寫一個包裝它的類並智能地提取請求的選項。

Python的標準庫configparser使用映射協議公開了INI樣式配置文件的部分和選項,因此您可以直接從該文件中檢索選項,就像它是字典一樣。

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

如果你明確希望提供使用該屬性標記的選項,創建一個覆蓋__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

有一個模塊負載PARAMS它的命名空間,然後將其導入和使用任何你想要的。
另請參閱相關問題here

相關問題