在循环中创建不同的实例

时间:2010-07-03 12:53:34

标签: c++

我将为特定的文件格式编写验证器(格式本身并不重要)。有大量文档可以指定格式的每个部分需要的样子,不同部分的关联方式等等。很多很多必须,SHALL,SHOULD,MAY等等。

我设想的架构如下:将文档加载到磁盘上的内存/单独文件中,然后对文档运行多次验证“传递”:每次传递都会检查是否符合一个且只有一个< / em>规则中指定的规则,如果传递失败,则会向stdout输出错误消息。每个pass都是一个实现公共接口的独立类,每个pass的实例都将在堆栈上创建,在文档上运行并收集Result(包含错误ID,消息,行/列号等)。然后将结果循环并打印出消息。然后可以轻松地为每次通过创建单元测试。

现在,我希望最终有数百个这些“传递”类。并且每一个都需要实例化一次,在文档上运行,并收集结果。

你知道我要去哪儿吗?如何在没有500行功能的情况下创建所有这些不同的实例,逐行创建每个实例?我想要某种循环。我也希望新的传递类在创建时以某种方式被“发现”,所以我不必手动添加实例化这些新类的行。

现在想一想,这一切似乎都让我想起了单元测试框架......

4 个答案:

答案 0 :(得分:1)

C ++是一种缺乏反射的静态语言,因此您将 以这样或那样的方式枚举您的类,无论是类名到工厂函数的映射,还是一个创建它们的显式函数,或cppunit风格的“注册”(与将它们放入静态地图相同)。

话虽如此,采用最简单的方式更改,并且不会引入太多不必要的工作和样板代码:在函数中创建它们的列表。

你说你将“最终”拥有数百个,而不是现在。 By the time you have hundreds of them, your design will have changed completely。如果所有这些实例的实例化都集中在一个函数中,则可以更容易地更改(统一)设计以添加依赖于先前验证器状态的验证器,向验证器构造函数添加参数,或者将验证器的简单列表替换为一些复合结构,比如条件验证器(例如,如果Y有某些结果,则运行X,如果启用了X和Y,则运行Z)。

如果它不再适合任务,那么像这样的简单代码也更容易丢弃,因为你只是倾向于投入复杂的设计并添加kludges而不是扔掉它。 :)

当您的代码库成熟时,您将确切知道您需要什么样的安排,但就目前而言,做最简单的事情


PS

使用文件本地宏,如果键入some_ptr<Foo> foo = new Foo()困扰你,宏就不那么脏了:)

电子。克。

#define NEW_V(cls, ...) do {\
    std::tr1::shared_ptr<Validator> v(new cls(__VA_ARGS__));\
    lst.push_back(v);\
} while(0)
...
std::list< std::tr1::shared_ptr<Validator> >
CreateValidators() {
    std::list< std::tr1::shared_ptr<Validator> > lst;
    CREATE_V(Foo);
    CREATE_V(Bar);
    CREATE_V(Baz, "baz");
    return lst;
}

答案 1 :(得分:1)

对于有这么多类的东西,我会选择一个允许你实例化所有已注册类的注册表。我写了some sample code,它显示了一个工厂函数和注册模式(你需要添加迭代注册函数的能力)。

关于这一点的好处是,已经使用类定义进行了注册,但系统中没有其他代码直接引用您的类。这是一个很好的脱钩。

注册模式的唯一问题是编译器有时会智能并删除它认为未使用的代码。解决方案各不相同。

答案 2 :(得分:0)

我会管理一个可能的解析器类列表(例如,通过名称)并使用factory pattern来创建具体的实现。解析器类应具有通用接口,使您能够使用相同的代码来移交信息和处理数据。

成功的关键是仅通过接口操作解析器并将解析器创建委托给一个工厂类(只有这一个知道具体实现并产生指向接口的指针)。这样,您可以通过在要构建的解析器列表中添加或删除解析器来激活和停用规则。

不是一个接一个地传递,你也可以按顺序执行:从输入中读取几行,然后将其移交给所有解析器。

答案 3 :(得分:0)

我认为这听起来像解析器的工作,例如ANTLR创建一个语法来检查你。它可以在C代码中创建一个解析器,可用于检查语法。这样,您对文档的未来更改也非常灵活。