用户界面-GUI和文本模式C++设计,以消除冗余(可选参数?功能过载?)



使用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;
}

相关内容

  • 没有找到相关文章

最新更新