如何在不违反封装的情况下实现撤销功能?

How to implement undo function without violating encapsulation?

让我们想象一个简单的棋盘游戏:

现在我想实现一个撤销功能。 我必须遵循 classes:

Game {
  (...)
  + placeFigure(int,int): void
  + isGameOver(): bool
}

Move {
  (...)
  + Move(Game,int,int)
  + execute(): void
  + undo(): void
}

History {
  - moves: List<Move>
  (...)
  + add(Move): void
  + undo(): void
}

我的问题是,为了撤消移动,我必须添加一个函数 removeFigure。 但是,不正确地调用此函数会导致无效状态。 我的另一个想法是使 Move 成为 Game 的嵌套 class。 然而,这会使 Game class 膨胀,并使将来添加其他可能的移动变得乏味。

我应该实施其中一个想法吗? 也许这个问题有更简单的解决方案?

不知道你的游戏的确切目标,也不知道你想到的其他类型的动作(我假设动作也会放置人物),这是我在 java 中可能会采用的方法您提出的当前限制。

/* Game.java */
import java.util.Stack;

public class Game
{
  protected static abstract class Move
  {
    protected final int x;
    protected final int y;

    protected Move(int x, int y) {
      this.x = x;
      this.y = y;
    }

    protected void execute(Game game) {
      game.placeFigure(x, y);
    }

    protected void undo(Game game) {
      game.removeFigure(x, y);
    }
  }

  private Stack<Move> history = new Stack<Move>();

  public void doMove(Move move) {
    move.execute(this);
    history.push(move);
  }

  public void undoMove() {
    if(history.empty()) {
      System.out.println("no move to undo");
    }
    else {
      Move move = history.pop();
      move.undo(this);
    }
  }

  protected void placeFigure(int x, int y) {
    System.out.println("place figure at: " + x + "," + y);
  }

  protected void removeFigure(int x, int y) {
    System.out.println("remove figure at: " + x + "," + y);
  }
}

/* DefaultMove.java */
public class DefaultMove extends Game.Move
{
  public DefaultMove(int x, int y) {
    super(x, y);
  }
}

/* SpecialMove.java */
public class SpecialMove extends Game.Move
{
  public SpecialMove(int x, int y) {
    super(x + 10, y + 10);
    System.out.println("SpecialMove displaces x and y by 10");
  }
}

/* Main.java */
public class Main
{
  public static void main(String[] arguments) {
    Game game = new Game();
    DefaultMove defaultMove = new DefaultMove(3,6);
    SpecialMove specialMove = new SpecialMove(4,5);
    game.doMove(defaultMove);
    game.doMove(specialMove);
    game.undoMove();
    game.undoMove();
    game.undoMove();
  }
}

打印:

SpecialMove displaces x and y by 10
place figure at: 3,6
place figure at: 14,15
remove figure at: 14,15
remove figure at: 3,6
no move to undo

也许这根本不是您要找的东西,但希望这能为您提供一些工作思路。让我知道您是否有完全其他的目标,我会看看是否可以满足。