GUI и текстовый режим C ++ предназначены для устранения избыточности (необязательный параметр «перегрузка функции») - PullRequest
1 голос
/ 17 июня 2011

Используя C ++, у меня есть текстовый режим и режим GUI, реализованный с использованием FLTK, выбранный параметром командной строки, и я вижу много избыточности в кодах, за исключением дополнительного параметра в случае GUI, который мне нужно передать в основной виджет окна Мне интересно, есть ли способы убрать избыточность? Может быть, у меня возникли проблемы с дизайном? Буду признателен за помощь, и, пожалуйста, дайте мне знать, если нужна дополнительная информация. Я подумал об использовании необязательного параметра, но не могу получить нулевую ссылку.

Вот скелет кодов, которые действительно похожи (не точно, но должны быть достаточно близко, чтобы увидеть общую структуру). Может быть еще несколько циклов или функций if / else, вложенных до того, как у меня будет один другой вызов с дополнительным параметром 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();
  }
}

Ответы [ 2 ]

1 голос
/ 17 июня 2011

Параметр не путь. Подклассы 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
}
0 голосов
/ 17 июня 2011

Можете ли вы сделать 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;

}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...