我遇到了有关访客模式和常量的问题。
假设在C ++中为小型游戏实现访问者模式实现,您可以在屏幕上绘制内容(取决于可绘制对象的内部状态),同时运行可以改变其内部状态的逻辑(非常多)任何你能想象到的游戏)。请原谅代码中的任何错误,因为这是在运行中完成的。
//Forward declaration of classes and visitor...
//class Game_actor; This one will be abstract, virtual, whatever.
class Game_actor_item;
class Game_actor_player;
class Game_actor_invisible;
class Visitor
{
public:
// virtual void visit(Game_actor& r)=0;
virtual void visit(Game_actor_player& r)=0;
virtual void visit(Game_actor_item& r)=0;
virtual void visit(Game_actor_invisible& r)=0;
};
然后,一些类似界面的基础知识:
//This one defines stuff that can be on the screen.
class Drawable
{
public:
virtual void draw(Screen&)=0;
};
//This one defines stuff that changes its state. Let's assume that do_logic
//returns an integer that means something to the controller and can be
//interpreted via a long list of "message_codes" (1=Add score, 2=Substract
//score, 3=Something else...). Each actor will run its logic and return its
//message, that will be stored and interpreted later. This is mostly crap,
//I know, but makes for a quick example.
class Game_actor
{
private:
float x;
float y;
public:
virtual int do_logic()=0;
void accept_visitor(Visitor& v)=0;
};
接下来,我们的对象层次结构:项目和播放器派生自actor,它定义了部分内部状态。当然,它们可以被吸引到屏幕上。有一个特定的演员不会被绘制,因为它是不可见的并控制其他东西。
class Game_actor_item: public Drawable, public Game_actor
{
//Lines and lines of code.
virtual void draw(Screen& s) {/* [...] */}
virtual int do_logic() {/* [...] */}
};
class Game_actor_player: public Drawable, public Game_actor
{
//Lines and lines of code.
virtual void draw(Screen& s) {/* [...] */}
virtual int do_logic() {/* [...] */}
};
class Game_actor_invisible: public Game_actor
{
//Lines and lines of code.
virtual int do_logic() {/* [...] */}
};
最后,访客专业化。我们将定义两个访客,一个将收集所有可绘制的演员,另一个将发送消息给游戏控制器。将从中收集可绘制的演员 它的基类的向量
class Visitor_drawing:public Visitor
{
private:
std::vector<Drawable *> draw_all_these;
public:
// virtual void visit(Game_actor& r)
virtual void visit(Game_actor_player& r) {draw_all_these.push_back(&r);}
virtual void visit(Game_actor_item& r) {draw_all_these.push_back(&r);}
//This one won't be drawn.
virtual void visit(Game_actor_invisible&) {}
std::vector<Drawable *> get_me_the_drawables() {return draw_all_these;}
}
class Visitor_logic:public Visitor
{
private:
std::vector<int> messages;
public:
// virtual void visit(Game_actor& r)
virtual void visit(Game_actor_player& r) {messages.push_back(r.do_logic());}
virtual void visit(Game_actor_item& r) {messages.push_back(r.do_logic());}
virtual void visit(Game_actor_invisible&) {messages.push_back(r.do_logic());}
std::vector<int> fetch_me_the_messages() {return messages;}
}
所以,这是我们的设置。它缺少“accept_visitor”方法,但我相信你会在这里得到这个想法。层次结构的每个最终分支都会使accept_visitor(访客&amp; v){v.visit(* this);}无效。
在循环的任何给定时间,我们收集可绘制的东西并运行逻辑:
std::vector<Game_actor*> actors;
while(loop)
{
Visitor_drawing dw;
Visitor_logic dl;
for(Game_actor * g : actors)
{
dw.visit(g);
dl.visit(g);
}
std::vector<Drawable *> draw_these=dw.get_me_the_drawables();
std::vector<int> messages=dl.fetch_me_the_messages();
for(Drawable * d : draw_these) d->draw(screen);
for(int * m : messages) interpret_message(m);
};
这就是我的问题:我真的想把我的对象保持在应有的位置。对此的一个必要条件是绘制它们永远不会改变它们的内部状态(例如,保存一个mutable int times_drawn),因此它们可以(并且应该(??))是const。做他们的逻辑可能会在每个给定的转弯处改变他们的状态(例如,在屏幕上移动它们)。
鉴于此特定设置,您将如何管理const和非const访问者?我已经尝试将基本访问者拆分为const和非const基类,以便它们执行
class Const_visitor
{
virtual void visit(const Thing&)=0;
};
class Non_const_visitor
{
virtual void visit(Thing&)=0;
};
class Visitor_drawing:public Const_visitor
{
virtual void visit(const Thing&)=0;
};
class Visitor_logic:public Non_const_visitor
{
virtual void visit(Thing&)=0;
};
但似乎我必须实现单独的“accept_visitor”方法,因为编译器不区分调用:
void accept_visitor_const(Const_visitor& v)=0;
void accept_visitor(Non_const_visitor& v)=0;
这会导致基本访问者类中的各种重复(基本上写两次,const和非const版本),然后在主循环中分离调用:不再有单个accept_visitor,你必须提前知道什么你期待的那种访客(副作用是它真的写着“我会接受这个承诺不改变我的内部的访客”,这有点可取)。
无论如何,我是否遗漏了其他任何不会彻底改变此设置的选项?这是一个合适且理想的选择吗?
一如既往,非常感谢。