2011-05-14 28 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模式集的“普遍性”隐藏的问题的方面。

确实,这可能是“矫枉过正”的问题,如你所描述的问题,但作为面向模式设计的练习,它可以非常有见地。