场景图更新回调设计

Scene Graph Update Callback Design

本文关键字:回调 更新      更新时间:2023-10-16

所以我使用开放场景图创建一个应用程序,我有一个从OSG的回调类扩展的回调类。 它只是一个回调,在场景图节点的更新事件遍历中调用每一帧。

我需要不同的回调类,在它们附加到的节点上执行不同的操作。 所以我有一个基回调类,我称之为控制器基:

class ControllerBase : public osg::NodeCallback
{
public:
    ControllerBase();
private:
    // operator is overridden here from NodeCallback and is called each frame.
    virtual void operator()(osg::Node * n, osg::NodeVisitor * nv);
}

operator() 也给了我回调附加的节点和一个节点访问者。 现在,根据节点的不同,它可能是不同的类,例如转换或开关。

所以我需要做一个动态转换,但对于每种可能的类型,节点可能是。所以:

class ControllerBase : public osg::NodeCallback
{
public:
    ControllerBase();
private:
    virtual void operator()(osg::Node * n, osg::NodeVisitor * nv)
    {
      Type1 * t1 = dynamic_cast<Type1*>(node);
      Type2 * t2 = dynamic_cast<Type1*>(node);
      Type3 * t3 = dynamic_cast<Type1*>(node);
    }
}

然后通过虚拟方法将它们发送出去,由我将附加到节点的特定控制器类继承。

class ControllerBase : public osg::NodeCallback
{
public:
    ControllerBase();
protected:
private:
    virtual void On_Frame(Type1*, osg::NodeVisitor) = 0;
    virtual void On_Frame(Type2*, osg::NodeVisitor) = 0;
    virtual void On_Frame(Type3*, osg::NodeVisitor) = 0;
    virtual void operator()(osg::Node * n, osg::NodeVisitor * nv)
    {
      Type1 * t1 = dynamic_cast<Type1*>(node);
      Type2 * t2 = dynamic_cast<Type1*>(node);
      Type3 * t3 = dynamic_cast<Type1*>(node);
      if(t1)
        On_Frame(t1, nv);
      if(t2)
        On_Frame(t2, nv);
      if(t3)
        On_Frame(t3, nv);
    }
}
class Type1_Controller
{
    public:
        Type1_Controler();
    private:
        virtual void On_Frame(Type1 * type, osg::NodeVisitor *nv) override
        {
            // Do type 1 related stuff here. 
        }
        virtual void On_Frame(Type2 * type, osg::NodeVisitor *nv) override
        {
            // Leave empty, not needed. 
        }
        virtual void On_Frame(Type3 * type, osg::NodeVisitor *nv) override
        {
            // Leave empty, not needed. 
        }
}

所以现在对于我拥有的每种类型的控制器,我必须实现剩余的空方法。 这感觉像是糟糕的设计,但我不知道如何编写更好的实现。 也许 3 种类型还不错,但随着我的进行,我可能还有更多要添加。 我想过使用模板类,但如果我没记错的话,我不能在模板类中使用虚拟方法。 我可以只使用带有空实现的非纯虚拟方法,我想然后可以选择覆盖。 什么是好的方法或建议?

osg::NodeVisitor 或多或少是 Visitor 设计模式的教科书实现。 (有关原始"四人帮"或GoF书籍的更多信息,请参阅 http://en.wikipedia.org/wiki/Design_Patterns)。

您可以在 t1 节点类中重写 accept(NodeVisitor) 以尝试转换为 t1 访问者类型,例如:

 Type1_Visitor* vis = dynamic_cast<NodeVisitor> nv;
 if(vis)
    vis->Type1Apply(*this);
 else
    nv->apply(*this);

当然,还有更多,但这是GoF书中提出的双重调度的一般思想。

根据您的

设计,看起来像类 - Type1, Type2, Type3都派生自osg::Node。在这种情况下,为什么要使用dynamic_cast并尝试确定运算符()重载中的类型?您可以在ControllerBase中执行此操作 -

virtual void operator()(osg::Node * n, osg::NodeVisitor * nv)
{
  On_Frame(n, nv);
}

那么在Type1_Controller中,Type2_Controller等都有一个单一的On_Frame方法,如——

virtual void On_Frame(osg::Node * n, osg::NodeVisitor *nv) override
{
   Type1 * t1 = dynamic_cast<Type1*>(n);
    if(t1)
    {
       // only if t1 do something
    }
 }