我有以下C ++设计问题。
假设我有以下课程:
class Model {
Model(int numberOfModels, int flag=-1) :
_models(numberOfModels), _flag(flag){ }
void buildModel(){
for (int id=0; id<_models.size(); ++id) {
if (flag == -1){
BuilderOne builder;
builder.build(&_models[id]);
}
else {
BuilderTwo builder;
builder.build(&_models[id]);
}
}
}
private:
vector<SimpleModel> _models;
int _flag;
};
其中成员函数“buildModel”构建“SimpleModel”对象的向量。 “BuilderOne”和“BuilderTwo”是不同的构建器类,它们都实现了“构建”方法(或者它们可以使用CRTP从相同的BaseBuilder类继承)。
但是上面的实现非常麻烦,因为构造器的类型应该在进入循环之前由“_flag”预先确定。我真正想要的是“buildModel”方法的以下实现:
void buildModel(){
if (flag == -1){
BuilderOne builder;
else
BuilderTwo builder;
for (int id=0; id<_models.size(); ++id)
builder.build(&_models[id]);
}
但是,上面的代码没有编译,因为1)在if语句之后对象“builder”不可见2)在编译时无法确定“builder”的类型。
通过在BaseBuilder中将“构建”方法设为虚函数,可以轻松实现上述功能。但由于我们库中的各种原因,实际上功能不被视为解决方案。但继承(如CRTP)是可以接受的。
有人可以帮忙解决这个问题吗?
答案 0 :(得分:1)
使用[insane] 要求无法使用虚拟功能时,您当前的实现就会被破坏。每次添加新的构建器类型时,您都必须更新Model
类。这可能正是你想要的(你的帖子不清楚),所以我试着用一个解决方案来覆盖这两种方法。
首先,您可以从利用静态多态性开始,并将主要功能放在函数模板中。这将帮助您避免缺少虚函数来减少使用它所需的代码量。
class Model
{
public:
template<class BuilderType>
BuilderType buildModel()
{
BuilderType builder;
// Perform other tasks here
for (int id = 0; id<_models.size(); ++id)
{
builder.build(&_models[id]);
}
// Perform other tasks here
return builder;
}
};
这将允许您使用对象类型,只要它实现一个build
函数,该函数获取指向SimpleModel
实例的指针。您还可以选择将构建器作为函数的参数,以允许自动类型推导。无论您是公开的,私人的还是受保护的,都取决于您以及您决定如何向前发展。这可能是您需要的全部内容,但如果您想将buildModel
功能限制为特定的一组构建器,则可以将其设置为受保护或私有,并提供简化构建过程的公共功能。
class Model
{
public:
void buildModel()
{
switch (flag_)
{
case -1:
buildModelByType<BuilderOne>(b);
break;
default:
buildModelByType<BuilderTwo>(b);
break;
}
}
protected:
template<class BuilderType>
BuilderType buildModelByType()
{
BuilderType builder;
// Perform other tasks here
for (int id = 0; id<_models.size(); ++id)
{
builder.build(&_models[id]);
}
// Perform other tasks here
return builder;
}
};
您是通过参数获取构建器还是返回构建过程的结果取决于您。你的帖子并没有具体说明问题的这一方面,但这应该很容易适应你所处的任何方面。