使用C++,我有一个文本模式和一个使用命令行选项选择的FLTK实现的GUI模式,我看到代码中有很多冗余,除了GUI情况下需要在主窗口小部件中传递的一个额外参数。我想知道是否有办法消除冗余?也许我的设计问题完全错了?我非常感谢您的帮助,如果需要其他信息,请告诉我。我曾想过使用可选参数,但不能使用NULL引用。
下面是一个非常相似的代码骨架(不确切,但应该足够接近以查看一般结构)。在我用额外的Window&参数,但这基本上就是结构,它实际上向下延续了几个级别。
谢谢你的帮助!
int Game::init(){
if (graphics){
std::unique_ptr<Window> window = std::unique_ptr<Window>(new Window(...))
return Fl::run();
} else {
play_game();
return 0;
}
}
void Window::init(Fl_Widget* w, void *uData){
Window* window = (Window*) uData;
Window->game.play_game(window);
//Window has a private game& that is constructed to be equal to the game above.
}
void Game::play_game(){
while(!over()){
foo();
bar();
}
}
void Game::play_game(Window& window){
while(!over()){
foo();
bar(window);
}
}
void Game::bar(){
if(!a()){
b();
} else {
c();
}
}
void Game::bar(Window& window){
if(!a()){
b();
} else {
c(window);
window.redraw();
}
}
一个类似但不同的问题涉及我如何处理FLTK中的静态函数,我有类似的代码,如下所示:
void Game::c(){
if(check_this()){
do_this();
}
}
void Game::c(Window& window){
Fl::run();
}
static void Window::call_back(Fl_Widget* w, void* uData){
Window* window = (Window *) uData;
if(window->game.check_this()){
window->do_this();
}
}
参数不是一条路。将Game
子类化是可行的。任何需要访问窗口的方法都是虚拟的,并在特定于窗口的子类中适当地重写。
class Game // I hate K&R braces, sorry
{
public:
enum GameType { cli, win };
static Game &GameFactory(GameType gt)
{
switch (gt)
{
case cli: return /* ref to instance of CliGame() */;
case win: return /* ref to instance of WinGame() */;
}
}
virtual int launch() = 0;
void foo();
void bar()
{
if (!a()) { b(); } else { c(); }
}
bool a();
void b();
virtual void c();
void play()
{
while (!over()) { foo(); bar(); }
}
private:
// need some sort of static management of instance of game, how is up to you
};
class WinGame : public Game
{
public:
virtual int launch()
{
window = std::unique_ptr<Window>(new Window(...));
return Fl::run(); // presumably calls play_game() sometime....
}
protected:
virtual void c()
{
// does whatever, using window *member* (not argument)
window.redraw();
}
private:
std::unique_ptr<Window> window;
};
class CliGame : public Game
{
virutal int launch()
{
play_game();
return 0;
}
virtual void c()
{
// does whatever
}
};
int main()
{
Game::GameType graphics;
// 'graphics' gets set somehow
Game &g = Game::GameFactory(graphics);
int retval = g.launch();
// etc
}
你能让window
成为你的Game
类的一员,这样你就不必传递太多了吗?
一种方法是使用模板,同时仍然保持Game
与窗口分离。然而,这将涉及接口更改,因此可能不合适。
首先,将您的窗口特定代码和控制台特定代码分开:
//class containing all your window management
class window
{
window()
{
//construct
std::unique_ptr<Window> m_window = std::unique_ptr<Window>(new Window(...));
}
void
redraw()
{
m_window.redraw();
}
private:
std::unique_ptr<Window> m_window;
};
//your console management
class console
{
};
然后用你的窗口/控制台选项加载你的游戏
从您的选项继承,以便您可以使用域特定的函数。
template<WindowOption>
class Game : public WindowOption
{
void
play_game()
{
while(!over()){
foo();
bar();
}
}
void
bar() //request for window functions deferred
{
if(!a()){
b();
} else {
c();
}
}
void b()
{
//console default
}
void c()
{
//console default
}
};
然后专门化需要调用特定于窗口的薄荷糖的函数。
template<>
Game<window>::b()
{
//with window specialisation
//can call window specific functions here as we have a window.
redraw();
}
template<>
Game<window>::c()
{
//with window specialisation
//can call window specific functions here as we have a window.
redraw();
}
然后呼叫:
int
main (int ac, char **av)
{
Game<window> gw;
Game<console> gc;
}