相关问题:link。
在上述问题的一个答案中,我建议使用访问者模式来解决我的类继承结构的一些问题。但是,我不确定是否可以在我的上下文中使用它,因为我的派生类可以是非类型模板。
为了展示问题,我使用了来自此来源的修改后的代码:http://sourcemaking.com/design_patterns/visitor/cpp/2。 下面的示例无法编译,因为无法定义虚拟模板方法。但是,我相信,代码演示了我想要实现的目标。有没有替代方案来解决这个问题?
// 1. Add an accept(Visitor) method to the "element" hierarchy
class Element
{
public:
virtual void accept(class Visitor &v) = 0;
};
template <unsigned int N>
class This: public Element
{
public:
/*virtual*/void accept(Visitor &v);
string thiss()
{
return "This";
}
};
class That: public Element
{
public:
/*virtual*/void accept(Visitor &v);
string that()
{
return "That";
}
};
// 2. Create a "visitor" base class w/ a visit() method for every "element" type
class Visitor
{
public:
template<unsigned int N>
virtual void visit(This<N> *e) = 0;
virtual void visit(That *e) = 0;
};
template<unsigned int N>
/*virtual*/void This<N>::accept(Visitor &v)
{
v.visit(this);
}
/*virtual*/void That::accept(Visitor &v)
{
v.visit(this);
}
// 3. Create a "visitor" derived class for each "operation" to do on "elements"
class UpVisitor: public Visitor
{
/*virtual*/void visit(This *e)
{
cout << "do Up on " + e->thiss() << '\n';
}
/*virtual*/void visit(That *e)
{
cout << "do Up on " + e->that() << '\n';
}
};
class DownVisitor: public Visitor
{
/*virtual*/void visit(This *e)
{
cout << "do Down on " + e->thiss() << '\n';
}
/*virtual*/void visit(That *e)
{
cout << "do Down on " + e->that() << '\n';
}
};
int main()
{
Element *list[] =
{
new This<3>(), new That()
};
UpVisitor up; // 4. Client creates
DownVisitor down; // "visitor" objects
for (int i = 0; i < 2; i++) list[i]->accept(up);
for (int i = 0; i < 2; i++) list[i]->accept(down);
}
答案 0 :(得分:2)
问题是你的Visitor
类与派生自Element
的类紧密结合。随着您扩展设计,这将比现有的更多。您可以通过提供定义可访问对象的所有要求的“目标”类来减少/消除正确的耦合。由于派生类的名称是一个公共属性,因此您也可以将存储和访问权限放入目标类中。
// 1. Define out visitor and destination interfaces
struct Destination
{
Destination(const std::string& name) : name_(name) {}
virtual std::string ident() const { return name_; }
const std::string name_;
};
struct Visitor
{
virtual void visit(Destination *e) = 0;
};
这样可以将访问者的要求与Element类分开,这似乎是您的意图。然后,您的This
和That
类继承自Destination
并提供必要的实施。
// 2. Define our element and it's derived classes
class Element
{
public:
virtual void accept(class Visitor &v) = 0;
};
template <unsigned int N>
class This: public Element, public Destination
{
public:
This() : Destination("This") {}
virtual void accept(Visitor &v)
{
v.visit(this);
}
};
class That: public Element, public Destination
{
public:
That() : Destination("That") {}
virtual void accept(Visitor &v)
{
v.visit(this);
}
};
现在,您的上下游客被简化为以下内容
// 3. Create a "visitor" derived class for each "operation" to do on "elements"
class UpVisitor: public Visitor
{
void visit(Destination *e) {
cout << "do Up on " + e->ident() << '\n';
}
};
class DownVisitor: public Visitor
{
void visit(Destination *e) {
cout << "do Down on " + e->ident() << '\n';
}
};
虽然我没有在上面的解决方案中更改它,但我建议更改visit
以获取引用而不是指针。由于C ++没有空引用的概念,这表明Destination
是必需的,因为指针可以被视为可选。