2011-05-14 106 views
3

想我再也噸文件名的my_dir/my_subdir,以某種方式格式化:設計定製的字符串過濾

data11_7TeV.00179691.physics_Egamma.merge.NTUP_PHOTON.f360_m796_p541_tid319627_00 
data11_7TeV.00180400.physics_Egamma.merge.NTUP_PHOTON.f369_m812_p541_tid334757_00 
data11_7TeV.00178109.physics_Egamma.merge.D2AOD_DIPHO.f351_m765_p539_p540_tid312017_00 

例如data11_7TeVdata_type00179691試驗號,NTUP_PHOTON的數據格式。

我想寫一個接口,做這樣的事情:

dataset = DataManager("my_dir/my_subdir").filter_type("data11_7TeV").filter_run("> 00179691").filter_tag("m = 796");      
// don't to the filtering, be lazy 
cout << dataset.count();       // count is an action, do the filtering 
vector<string> dataset_list = dataset.get_list(); // don't repeat the filtering 
dataset.save_filter("file.txt", "ALIAS");   // save the filter (not the filenames), for example save the regex 
dataset2 = DataManagerAlias("file.txt", "ALIAS"); // get the saved filter 
cout << dataset2.filter_tag("p = 123").count(); 

我想偷懶的行爲,例如沒有真正的濾波具有像countget_list任何行動之前完成。如果已經完成,我不想重做過濾。 我只是學習一些關於設計模式,我想我可以使用:

  • 一個抽象基實現filter*方法
  • 工廠從調用的方法來決定類AbstractFilter裝飾使用
  • 我每次叫filter *方法我返回一個裝飾類,例如時間:

AbstractFilter::filter_run(string arg) { 
    decorator = factory.get_decorator_run(arg); // if arg is "> 00179691" returns FilterRunGreater(00179691) 
    return decorator(this); 
} 

  • 代理是建立一個正則表達式過濾的文件名,但不要做過濾

我也在學習jQuery和我使用的是類似鏈接機制。

有人可以給我一些提示嗎?有沒有什麼地方可以解釋這樣的設計?設計必須非常靈活,特別是處理文件名中的新格式。

回答

3

我相信你在設計模式方面過分複雜化,並掩蓋了底層匹配/索引問題。從磁盤獲取完整的目錄列表可能要比它返回的文件名的內存過濾要貴幾個數量級,而前者需要先完成,然後才能在任何dataset上執行count()get_list()(儘管您可以在dataset上提出一些更復雜的迭代器操作)。

如前所述,真正的功能挑戰可能在索引文件名,以便您可以快速找到匹配。但是,即使這樣也不太可能,因爲你大概是從獲取文件名數據集到實際打開這些文件,這又慢了幾個數量級。因此,索引的優化可能不會對整體程序的性能產生任何可觀的影響。

但是,假設你閱讀所有匹配的目錄條目到一個數組A.

現在,過濾,看來你的要求,通常可使用std::multimapfind()lower_bound()upper_bound()滿足。處理它的最通用的方法是爲數據類型,運行編號,數據格式,值m值值tid等分別映射到A中的索引列表。然後,您可以使用現有的STL算法來查找各個過濾器的結果通用的指標。

如果您碰巧沒有提及您的數據和過濾需求(很有可能)的見解/限制,那麼可以進行很多優化。例如:

  • 如果你知道一個特定的過濾器將始終使用,並立即切斷潛在匹配降至可控數量(例如<〜100),那麼你可以先使用它,並訴諸蠻力搜索以供後續過濾。

另一種可能性是個別文件名的屬性提取到的結構:std::string data_type;std::vector<int> p;等,然後寫表達式評估器支撐謂詞像「P包括924和DATA_TYPE ==‘XYZ’」,雖然通過本身借給本身進行暴力比較而不是更快的基於索引的匹配。

我知道你說過你不想使用外部庫,但是如果你的需求真的處於更精細的結尾,那麼內存數據庫和類似SQL的查詢能力可以爲你節省很多的痛苦。

0

我建議從boost迭代器庫開始 - 例如filter iterator

(而且,當然,升壓包括一個非常漂亮的正則表達式庫)。

+0

正則表達式不是問題。我會執行withoud第三部分庫 – 2011-05-16 21:05:26

1

我會用一個策略模式。你的DataManager構造一個DataSet類型,並且DataSet有一個FilteringPolicy分配。默認值可以是NullFilteringPolicy,這意味着沒有過濾器。如果DataSet成員函數filter_type(string t)被調用,它會使用新的過濾器策略類替換過濾器策略類。新的可以通過filter_type參數進行工廠構造。諸如filter_run()之類的方法可用於將過濾條件添加到FilterPolicy中。在NullFilterPolicy的情況下,它只是無操作。這對我來說似乎很直接,我希望這有助於。

編輯: 要解決方法鏈,你只需要返回* this;例如返回對DataSet類的引用。這意味着您可以將DataSet方法鏈接在一起。這是C++ iostream庫在實現運算符>>或運算符< <時所執行的操作。

1

首先,我認爲你的設計非常聰明,適合你試圖建模的那種行爲。

無論如何,我的理解是,您正在嘗試並構建一種「域特定語言」,從而您可以鏈接表示動作的「動詞」(各種過濾方法)或連接「實體」(變異性由可能存在的不同命名格式表示,儘管您對此沒有任何說明)。

在這方面,Martin Floler的書「Domain Specific Languages」中有一個非常有趣的討論。只給你的是什麼味道有關,here你可以找到關於「方法鏈」模式的有趣的討論,定義爲:

「做修飾方法返回主機對象,以便多個修改可在單個表達式中調用。「

正如你所看到的,這個模式描述了你在設計中定位的鏈接機制。

Here您有定義此類DSL時發現有趣的所有模式的列表。再次,你會很容易地發現有幾種專門的模式,你也在設計中暗示或者描述爲更通用的模式(比如裝飾器)。其中一些是:正則表表格Lexer,方法鏈接,表達式生成器等等,還有更多可以幫助您進一步指定您的設計。總而言之,我可以通過說我在你的規範中看到一個「命令處理器」模式的地方來添加我的糧食,但我相當確信,通過部署Fowler建議你的強大抽象,能夠提出更加具體和精確的設計,涵蓋了目前僅由GoF模式集的「普遍性」隱藏的問題的方面。

確實,這可能是「矯枉過正」的問題,如你所描述的問題,但作爲面向模式設計的練習,它可以非常有見地。