【问题标题】:How to implement undo function without violating encapsulation?如何在不违反封装的情况下实现撤消功能?
【发布时间】:2021-10-22 07:02:59
【问题描述】:

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

  • 每回合可以放置一个人物。
  • 不得删除人物。
  • 当满足特定条件时,游戏结束。

现在我想实现一个撤销功能。 我必须参加以下课程:

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 的嵌套类。 但是,这会使 Game 类膨胀,并且使将来添加其他可能的动作变得乏味。

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

【问题讨论】:

    标签: oop design-patterns


    【解决方案1】:

    在不知道您的游戏的确切目标或您想到的其他类型的移动(我假设移动也放置数字)的情况下,这是我在 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
    

    也许这根本不是您想要的,但希望这能给您一些想法。让我知道您是否有完全其他的目标,我会看看我是否可以满足。

    【讨论】:

    • 我的描述含糊不清,因为我想获得一些意见来自己解决问题。在我看来,让removeFigureGame.Move 内部可访问,然后扩展Game.Move 类是一个好方法。谢谢!
    猜你喜欢
    • 2019-03-18
    • 1970-01-01
    • 1970-01-01
    • 2016-06-29
    • 2013-01-30
    • 2011-05-27
    • 1970-01-01
    • 1970-01-01
    • 2012-12-16
    相关资源
    最近更新 更多