Đọc qua thì thấy nó bảo giống với callback (là thể loại delegate …).
Thực ra là không có cái gì liên quan đến cái đấy hết! :v

Xét tình huống điều khiển sự di chuyển của nhân vật.
Thông thường chúng ta sẽ làm như sau:

void InputHandler::handleInput()
{
  if (isPressed(BUTTON_X)) jump();
  else if (isPressed(BUTTON_Y)) fireGun();
  else if (isPressed(BUTTON_A)) swapWeapon();
  else if (isPressed(BUTTON_B)) lurchIneffectively();
}

Player sẽ được điều khiển trong các hàm kia!

Giờ ta có 1 cách tiếp cận mới:
1. Tạo 1 interface player IPlayer khai báo các hàm jump,fire,… , nơi mà các nhân vật (trường hợp có nhiều nhân vật để điều khiển) phải implement những methods đó!
2. Tiếp theo ta tạo 1 interface ICommand, định nghĩa 1 method với đầu vào là IPlayer execute(IPlayer player), các lớp con ví dụ như JumpCommand sẽ implement và thực hiện gọi hàm player.Jump() trong hàm execute của nó!

Lợi ích:
1. Lúc này ta không cần quan tâm đến nhân vật đang điều khiển là ai, chỉ cần nó implement IPlayer là chúng ta có thể điều khiển được nó mà không cần viết thêm gì!

class Command
{
public:
  virtual ~Command() {}
  virtual void execute(GameActor& actor) = 0;
};
class JumpCommand : public Command
{
public:
  virtual void execute(GameActor& actor)
  {
    actor.jump();
  }
};
Command* InputHandler::handleInput()
{
  if (isPressed(BUTTON_X)) return buttonX_;
  if (isPressed(BUTTON_Y)) return buttonY_;
  if (isPressed(BUTTON_A)) return buttonA_;
  if (isPressed(BUTTON_B)) return buttonB_;

  // Nothing pressed, so do nothing.
  return NULL;
}
Command* command = inputHandler.handleInput();
if (command)
{
  command->execute(actor);
}

2. Một lợi ích khác là thực hiện implement Undo và Redo
– Thêm trong phương thức execute của ICommand, ta lưu trạng thái hiện tại của player trước khi move tớ trạng thái tiếp theo, khai báo thêm 1 phương thức Undo nữa, trong đó ta thực hiện move về vị trí mà ta đã lưu lại

class MoveUnitCommand : public Command
{
public:
  MoveUnitCommand(Unit* unit, int x, int y)
  : unit_(unit),
    xBefore_(0),
    yBefore_(0),
    x_(x),
    y_(y)
  {}

  virtual void execute()
  {
    // Remember the unit's position before the move
    // so we can restore it.
    xBefore_ = unit_->x();
    yBefore_ = unit_->y();

    unit_->moveTo(x_, y_);
  }

  virtual void undo()
  {
    unit_->moveTo(xBefore_, yBefore_);
  }

private:
  Unit* unit_;
  int xBefore_, yBefore_;
  int x_, y_;
};
Advertisements