我的问题是:(上述|是什么)创建非侵入式前端的正确方法?
我用一个简化的例子来解释我的问题。
我有一个实现二叉树的后端:
// Back-end
struct Node
{
Label label;
Node* r, l;
};
我现在想实现前端以图形方式打印树。所以我的想法是通过包装后端来扩展图形属性:
// Front-end
struct Drawable
{
uint x, y;
};
class Visitor;
template <class T> struct GNode : public Drawable
{
T* wrapped;
template <class V> void accept(V& v); // v.visit(*this);
}
现在存在创建访问者以打印二叉树的问题:
struct Visitor
{
void visit(GNode<Node>& n)
{
// print the label and a circle around it: ok.
if (n.wrapped.l) // l is a Node, not a GNode, I can't use the visitor on it
// Problem: how to call this visitor on the node's left child?
// the same with n.wrapped.r
};
};
如评论中所述,后端不使用我的扩展类。
编写GNode“是”节点也不是解决方案,因为我必须将Node类中的accept()方法设置为虚拟方法并在GNode中覆盖它,但是我无法修改后端。然后,有人也可以说不需要在后端声明accept(),将Node *向下转换为GNode *即可。是的,它可以工作,但是很沮丧……
就我而言,我有约10种节点(它是一个图形),所以我正在寻找一种优雅,灵活的东西,并使用尽可能少的代码行(因此有包装模板的想法):)
非常感谢你。
最佳答案
完全分离代码是不可能的。他们必须说话。如果您确实要最大程度地实施去耦,则应使用某种IPC / RPC机制,并且该机制具有两个不同的程序。
话虽如此-我不喜欢访客模式。
您有一个图形对象,该对象与行为对象链接。行为和图形之间可能存在规则,例如边界不能重叠。
您可以在图形和行为之间建立实体关系,这是一个业务逻辑问题...
您将需要一些保存您的绘图上下文(img,屏幕,缓冲区)的thungus。
class DrawingThungus {
void queue_for_render(Graphical*);
void render();
};
图形用户将与行为具有继承关系或构图关系。
无论如何,他们将具有进行绘图所需的界面。
//abstract base class class Graphical {
get_x();
get_y();
get_icon();
get_whatever();
};
如果您发现您的渲染器根据图形对象的类型而成为基于案例的对象,我建议将案例推至图形对象,并重构为
get_primitives_list()
,其中返回所需的基元以使图形对象返回(I假设您在某种程度上拥有核心图元,直线,圆,圆弧,标签等)。我一直发现,OO分析很容易浪费精力,应该仅对即将完成的任务进行足够的分析。 YAGNI是一个伟大的原则。