c ++稍后保留指令

c++ Hold instructions for a later time

我正在尝试设计一个 UIDraw 方法。我想在主要的 Draw 方法中声明要绘制的 UI 元素但是随后在代码中有一个单独的 UIDraw 方法。所以我需要一种方法来存储在这个新函数中执行的指令。我希望这是有道理的。 像这样:

        Draw();
        DrawUI();

但是说什么UI在Draw()函数中绘制。 关于如何解决这个问题有什么想法吗?

根据您确切的需要,有很多方法可以解决这个问题。 OO 世界中流行的一种方法是所谓的 Command Pattern(其他编程范例中也存在类似的方法,它们只是具有不同的名称,或者被认为非常明显,甚至根本没有特定的名称)。

基本思路是这样的:你想执行某个命令,但是你想执行命令的时间和你决定执行什么命令的时间是不一样的。所以解决这个问题的方法是简单地创建一个包含执行命令所需信息的对象,将该对象传递到决定何时执行的地方,然后该代码可以 运行 命令随心所欲。

这是在 C++ 中可能看起来像的模型(注意:没有实际编译此代码,可能包含小错误 - 只是为了传达这个想法)。

#include <memory>
#include <vector>

/// this is an abstract class that gives us an interface to use
class DrawCommand {
  public:
  virtual void Draw() = 0;
};

/// one kind of thing you might want to draw
class DrawTree : public DrawCommand {
  public:
  void Draw() override {
     // tree drawing code
  }
};

/// another kind of thing you might want to draw
class DrawCat : public DrawCommand {
  public:
  void Draw() override {
    // cat drawing code
  }
};

/// we can even come up with ways to combine these in interesting ways
class DrawABunchOfThings : public DrawCommand {
  std::vector<std::unique_ptr<DrawCommand>> things;
  public:
  DrawABunchOfThings(std::vector<std::unique_ptr<DrawCommand>> things)
    : things{std::move(things)}
  {}

  void Draw() override {
    for(auto &thing : things) {
      thing->Draw();
    }
  }
};

/// this is where we decide what we will draw
std::unique_ptr<DrawCommand> PrepareDraw() {
  if(someCondition) {
    // just a cat
    return std::make_unique<DrawCat>();
  } else if(someOtherCondition) {
    // just a tree
    return std::make_unique<DrawTree>();
  } else {
    // forest with a cat hidden inside
    return std::make_unique<DrawABunchOfThings>(
      std::vector<std::unique_ptr<DrawCommand>>{
        std::make_unique<DrawTree>(),
        std::make_unique<DrawTree>(),
        std::make_unique<DrawCat>()
        std::make_unique<DrawTree>(),
      }
    );
  }
}

/// this is where we will do the actual drawing
/// note that any arbitrary amount of code can go between
/// PrepareDraw and ExecuteDraw
void ExecuteDraw(DrawCommand &command) {
  // this can of course have a bunch of elaborate
  // code here as well -- also, DrawCommand::Draw might
  // take extra parameters here, like 2D or 3D transforms,
  // time since we last drew something, or whatever
  command.Draw();
}

请注意,如果你只需要这个东西的一个方法,C++ 已经以 std::function 的形式提供了它,所以你可以只说 using DrawCommand = std::function<void()>; 并完成它,这也立即允许您将其与 lambdas 一起使用:

int nTimes = 10;
DrawCommand drawNTimesCommand = [nTimes]() {
  for(int i = 0; i < nTimes; ++i) {
    // draw something
  }
};

// --- any code you like here ---

// actually execute the draw command
drawNTimesCommand();