实用的设计模式

一、访问者模式(Visitor)

​​  osg中节点node系统是一个庞大复杂的类层次体系,包括叶节点Geode、组节点Group、变换节点Transform、几何节点Drawable等等,他们都是Node的子类。开发功能时,想要访问到某个节点的子节点只能通过getChildren()接口获取到Node*类型的指针变量,并动态类型转换为子类指针。

​​  osg支持osg::NodeVisitor类来实现访问者模式。也就是,一个osg::NodeVisitor派生类遍历一个场景图,访问每一个节点,并应用用户定义的操作。他是更新,事件与裁剪遍历(例如osgUtil::CullVisitor)以及其他一些场景图工具,包括osgUtil::SmoothingVisitor,osgUtil::Simplifier与osgUtil::TriStripVisitor的实现的基类,所有这些类都会遍历指定的子场景图并且在osg::Geode节点中的几何体上应用多边形修改。基于双分派理论,开发者可以使用特定的操作请求自定义其访问者,并且在运行时将访问者绑定到不同的元素类型而不修改元素接口。这是一种无需定义多个新元素子类来扩展元素功能的好方法。

virtual void apply( osg::Node& );
virtual void apply( osg::Geode& );
virtual void apply( osg::Group& );
virtual void apply( osg::Transform& );

​​  比如说设计访问者基类ToolBaseVisitor和访问对象基类ToolBase。

class ToolBaseVisitor
{
public:
virtual void excute(QSharedPointer<ToolBase> tool)=0;
};

​​  实现更新的访问具体类UpdateToolVisitor和具体的测量工具类。并可以通过模板方式调用不同的visitor。

class UpdateToolVisitorpublic ToolBaseVisitor
{
public:
virtual void excute(QSharedPointer<ToolBase> tool)
{
tool->action(*this);
}
};
class MeasureTool:public ToolBase
{
virtual void action(const UpdateToolVisitor& visitor)
{
///concrete method
}
};

​​  所谓双分派就是指的访问者和被访问者都是多态的,设想一下如果仅仅只有被访问者是多态的,我们可以用父类指针执行子类实际的方法,那么每添加一种访问就要在父类加一个虚函数,外部调用就要判断访问者类型,然后根据类型来调用具体的方法,非常不灵活。

二、命令模式(Command)

​​  命令模式可以将调用函数的参数封装,封装后的对象可以记录调用过程,用于撤销重做。

​​  比较简单的例子如下,命令模式响应不同的操作:

///命令基类
class Command
{
public:
virtual ~Command() {}
virtual void execute() = 0;
};
///实际的操作命令子类
class JumpCommand : public Command
{
public:
virtual void execute() { jump(); }
};
class FireCommand : public Command
{
public:
virtual void execute() { fireGun(); }
};
///外部调用
void InputHandler::handleInput()
{
if (isPressed(BUTTON_X)) buttonX_->execute();
else if (isPressed(BUTTON_Y)) buttonY_->execute();
else if (isPressed(BUTTON_A)) buttonA_->execute();
else if (isPressed(BUTTON_B)) buttonB_->execute();
}

​​  队列实现撤销重做:

class Command
{
public:
virtual ~Command() {}
virtual void execute() = 0;
virtual void undo() = 0;
};
class MoveUnitCommand : public Command
{
public:
MoveUnitCommand(Unit* unit, int x, int y)
: unit_(unit),
xBefore_(0),
yBefore_(0),
x_(x),
y_(y)
{}
virtual void execute()
{
// 保存移动之前的位置
// 这样之后可以复原。
xBefore_ = unit_->x();
yBefore_ = unit_->y();
unit_->moveTo(x_, y_);
}
virtual void undo()
{
unit_->moveTo(xBefore_, yBefore_);
}
private:
Unit* unit_;
int xBefore_, yBefore_;
int x_, y_;
};
posted @   王小于的啦  阅读(21)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· 写一个简单的SQL生成工具
点击右上角即可分享
微信分享提示