如何在不违反封装的情况下实现撤销功能?
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
也许这根本不是您要找的东西,但希望这能为您提供一些工作思路。让我知道您是否有完全其他的目标,我会看看是否可以满足。
让我们想象一个简单的棋盘游戏:
- 每一回合你可以放置一个人物。
- 您不能删除图形。
- 当满足特定条件时,游戏结束。
现在我想实现一个撤销功能。 我必须遵循 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
也许这根本不是您要找的东西,但希望这能为您提供一些工作思路。让我知道您是否有完全其他的目标,我会看看是否可以满足。