OSG笔记:NodeVisitor原理

模仿OSG的NodeVisitor机制实现简易访问者模式(Visitor Pattern)

Node.h

#pragma once
#include <iostream>
#include <vector>
#include "NodeVisitor.h"
#include "NodeCallback.h"

class NodeVisitor;
class Node
{
public:
	Node();
	Node(int);
	~Node();
	
public:
	void addChild(Node*);
	void show();

public:
	//接收一个访问器,并执行访问器的apply函数(将自身传入nv.apply()),
	//nv的apply函数中执行具体的访问操作
	void accept(NodeVisitor& nv);

	//向下一级节点推进访问器
	void traverse(NodeVisitor& nv);

public:
	void setCallback(NodeCallback*);
	NodeCallback* getCallback();
	

protected:
	int _num;
	std::vector<Node*> _children;
	NodeCallback* _callback;
};

Node.cpp

#include "Node.h"

Node::Node()
{
}

Node::Node(int num) : _num(num)
{
}

Node::~Node()
{
}

void Node::addChild(Node* child)
{
	_children.push_back(child);
}

void Node::show()
{
	std::cout << _num << std::endl;
}

void Node::accept(NodeVisitor & nv)
{
	nv.apply(*this);
}

void Node::traverse(NodeVisitor & nv)
{
	for (auto child = _children.begin(); child != _children.end(); child++)
	{
		(*child)->accept(nv);
	}
}

NodeVisitor.h

#pragma once
#include "Node.h"

class Node;
class NodeVisitor
{
public:
	NodeVisitor();
	~NodeVisitor();

public:
	//向下一个要访问的节点推进
	void traverse(Node& node);

	//访问节点,并执行访问器中自定义的节点操作
	void apply(Node& node);
};

NodeVisitor.cpp

#include "NodeVisitor.h"

NodeVisitor::NodeVisitor()
{
}

NodeVisitor::~NodeVisitor()
{
}

void NodeVisitor::traverse(Node& node)
{
	node.traverse(*this);
}

void NodeVisitor::apply(Node& node)
{
	node.show(); //自定义行为
	traverse(node);
}

#include "NodeVisitor.h"

NodeVisitor::NodeVisitor()
{
}

NodeVisitor::~NodeVisitor()
{
}

void NodeVisitor::traverse(Node& node)
{
	node.traverse(*this);
}

void NodeVisitor::apply(Node& node)
{
	node.show(); //自定义行为
	traverse(node);
}

main.cpp

#include "Node.h"
#include "NodeVisitor.h"
#include <iostream>
#include <vector>

int main()
{
	std::vector<Node> nodes;
	for (int i = 1; i <= 5; i++)
	{
		nodes.push_back(Node(i));
	}
	nodes[0].addChild(&nodes[1]);
	nodes[0].addChild(&nodes[2]);
	nodes[1].addChild(&nodes[3]);
	nodes[1].addChild(&nodes[4]);

	NodeVisitor nv;
	nodes[0].accept(nv);

	system("pause");
	return 0;
}

节点树:
在这里插入图片描述
DFS结果:1、2、4、5、3

访问者模式(访问器模式、Visitor Pattern)流程:

  1. 待访问节点node接收一个访问器nv
NodeVisitor nv;
    node.accept(nv);
  1. nv访问该节点
nv.apply(*this);
void NodeVisitor::apply(Node & node)
{
/********用户自定义对节点的操作*******/
	node.show();
/*************************************/
	traverse(node);//推进到下一个节点
}
  1. 操作完成后,nv访问继续下一个节点
traverse(node);//推进到下一个节点
void NodeVisitor::traverse(Node& node)
{
	node.traverse(*this);
}

nv的traverse直接调用节点的traverse方法,推进到下一个节点(子节点、父节点等)

void Node::traverse(NodeVisitor & nv)
{
	for (auto child = _children.begin(); child != _children.end(); child++)
	{
		(*child)->accept(nv);
	}
}