在 ArrayLists 中使用命令模式进行撤消和重做
Using Command pattern for undo and redo in ArrayLists
所以我有一个程序,您可以在其中登录和 add/remove 朋友进出 friends
arraylist。我也可以喜欢某个东西,那个东西将被存储到 likes
arraylist 中。我被要求为我执行的任何操作设置撤消和重做选项。
所以我想加apple为好友。之后,当我 select 撤消选项时,我可以撤消该操作,这样 apple 就不会成为我的朋友。当输入是我输入要存储到 friends
数组列表中的任何名称或单词时,我如何使用 Command Pattern
来处理这个问题?
我做了一些研究,发现使用命令模式可能是我最好的选择,因为这必须在我已经拥有的 Facebook Class 下完成。我假设我将不得不使用两个不同的堆栈,但我有点迷失了主题。
我决定添加我已有的部分内容,以便在我需要做的事情和我的程序能做的事情上获得更多帮助。
在驱动程序中
Facebook facebook1 = new Facebook();
if (userInput == 6)
{
System.out.println("Login");
String operand1 = getOperand("What is the Username? ");
String operand2 = getOperand("What is the Password? ");
System.out.println("Enter a friend to be added. ");
String operand3 = getOperand("What is the Username? ");
facebook1.friend(operand3);
}
if (userInput == 7)
{
System.out.println("Login");
String operand1 = getOperand("What is the Username? ");
String operand2 = getOperand("What is the Password? ");
System.out.println("Enter a friend to be removed. ");
String operand3 = getOperand("What is the Username? ");
facebook1.defriend(operand3);
}
if (userInput == 12)
{
System.out.println("Login");
String operand1 = getOperand("What is the Password? ");
facebook1.undo();
}
if (userInput == 13)
{
System.out.println("Login");
String operand1 = getOperand("What is the Password? ");
facebook1.redo();
}
在 Facebook Class
ArrayList<FacebookUser> recommendedFriends = new ArrayList<FacebookUser>();
void friend(String newFriend)
{
boolean positiveChecker = false;
for (int i = 0; i < recommendedFriends.size(); i++)
{
if (recommendedFriends.get(i).toString().equalsIgnoreCase(newFriend))
{
System.out.println("Error: This friend already exists.");
positiveChecker = true;
}
}
if (positiveChecker == false)
{
FacebookUser friend = new FacebookUser(newFriend, newFriend );
recommendedFriends.add(friend);
System.out.println(friend + " is now your friend.");
}
positiveChecker = false;
}
void defriend(String formerFriend)
{
boolean positiveChecker = false;
for (int i = 0; i < recommendedFriends.size(); i++)
{
if (recommendedFriends.get(i).toString().equalsIgnoreCase(formerFriend))
{
recommendedFriends.remove(i);
System.out.println(formerFriend + " has been removed from your friends list.");
positiveChecker = true;
}
if (recommendedFriends.size() == (i + 1) && recommendedFriends.get(i).toString() != formerFriend
&& positiveChecker == false)
{
System.out.println("Error: There is no friend with this username.");
}
}
positiveChecker = false;
}
public interface Command
{
public void undo();
public void redo();
}
您误解了命令模式的工作原理。您想要 Commands
的单独 List
,其中每个 Command 实例代表一个 action。
所以你会想要这样的东西:
List<Command> actionStack;
然后有像
这样的东西
public class AddCommand implements Command {
private final void List<FacebookUser> userList;
private final void FacebookUser newUser;
public AddCommand(List<FacebookUser> userList, FacebookUser newUser) {
this.userList = userList;
this.newUser = newUser;
}
@Override
public void undo() {
userList.remove(newUser);
}
@Override
public void redo() {
userList.add(newUser);
}
}
当你撤消 2 件事然后做一个全新的动作时,你需要 "forget" "redo history" 并用新命令替换它,对吗?
例如...
- 加好友吉姆
- 添加好友账单
- 加好友吉尔
- 删除吉姆
- 撤消
- 撤消
状态应为 "Jim" 和 "Bill"。
所以你真的只需要一个列表和一个指向当前 "command" 的指针,例如...
// Note: NOT thread safe!
public class CommandStack {
private List<Command> commands = Collections.emptyList();
private int nextPointer = 0;
public void doCommand(Command command) {
List<Command> newList = new ArrayList<>(nextPointer + 1)
for(int k = 0; k < nextPointer; k++) {
newList.add(commands.get(k));
}
newList.add(command);
commands = newList;
nextPointer++;
// Do the command here, or return it to whatever called this to be done, or maybe it has already been done by now or something
// (I can only guess on what your code currently looks like...)
command.execute();
}
public boolean canUndo() {
return nextPointer > 0;
}
public void undo() {
if(canUndo()) {
nextPointer--;
Command commandToUndo = commands.get(nextPointer);
// Undo the command, or return it to whatever called this to be undone, or something
command.undo();
} else {
throw new IllegalStateExcpetion("Cannot undo");
}
}
public boolean canRedo() {
return nextPointer < commands.size();
}
public void redo() {
if(canRedo()) {
commandToDo = commands.get(nextPointer);
nextPointer++;
// Do the command, or return it to whatever called this to be re-done, or something
commandToDo.execute();
} else {
throw new IllegalStateException("Cannot redo");
}
}
}
如果我有...
interface Command { /* execute / undo etc */ }
public class AddFriendCommand implements Command {
private String friendName;
// ... other fields, constructor / getters etc ...
public void execute() {
// Actually do it...
System.out.println("Added friend " + name);
}
public void undo() {
// Undo it...
System.out.println("Removed friend " + name);
}
}
public class RemoveFriendCommand implements Command {
private String friendName;
// ... other fields, constructor / getters etc ...
public void execute() {
// Actually do it, maybe throw exception if friend does not exist?
// (that would have to be a runtime exception unless you want the interface's method to throw stuff);
System.out.println("Removed friend " + name);
}
public void undo() {
// Undo it...
System.out.println("Added friend " + name);
}
}
您可以使用...重复上述序列
CommandStack stack = new CommandStack();
stack.doCommand(new AddFriendCommand("Jim"));
stack.doCommand(new AddFriendCommand("Bill"));
stack.doCommand(new AddFriendCommand("Jill"));
stack.doCommand(new RemoveFreindCommand("Jim"));
stack.undo();
stack.undo();
如果您现在执行了一个新命令(通过 doCommand),它会忘记您曾经添加过 "Jill" 或删除过 "Jim",而是现在会记住新命令和命令的其余部分无法撤销的历史。
希望对您有所帮助。
所以我有一个程序,您可以在其中登录和 add/remove 朋友进出 friends
arraylist。我也可以喜欢某个东西,那个东西将被存储到 likes
arraylist 中。我被要求为我执行的任何操作设置撤消和重做选项。
所以我想加apple为好友。之后,当我 select 撤消选项时,我可以撤消该操作,这样 apple 就不会成为我的朋友。当输入是我输入要存储到 friends
数组列表中的任何名称或单词时,我如何使用 Command Pattern
来处理这个问题?
我做了一些研究,发现使用命令模式可能是我最好的选择,因为这必须在我已经拥有的 Facebook Class 下完成。我假设我将不得不使用两个不同的堆栈,但我有点迷失了主题。
我决定添加我已有的部分内容,以便在我需要做的事情和我的程序能做的事情上获得更多帮助。
在驱动程序中
Facebook facebook1 = new Facebook();
if (userInput == 6)
{
System.out.println("Login");
String operand1 = getOperand("What is the Username? ");
String operand2 = getOperand("What is the Password? ");
System.out.println("Enter a friend to be added. ");
String operand3 = getOperand("What is the Username? ");
facebook1.friend(operand3);
}
if (userInput == 7)
{
System.out.println("Login");
String operand1 = getOperand("What is the Username? ");
String operand2 = getOperand("What is the Password? ");
System.out.println("Enter a friend to be removed. ");
String operand3 = getOperand("What is the Username? ");
facebook1.defriend(operand3);
}
if (userInput == 12)
{
System.out.println("Login");
String operand1 = getOperand("What is the Password? ");
facebook1.undo();
}
if (userInput == 13)
{
System.out.println("Login");
String operand1 = getOperand("What is the Password? ");
facebook1.redo();
}
在 Facebook Class
ArrayList<FacebookUser> recommendedFriends = new ArrayList<FacebookUser>();
void friend(String newFriend)
{
boolean positiveChecker = false;
for (int i = 0; i < recommendedFriends.size(); i++)
{
if (recommendedFriends.get(i).toString().equalsIgnoreCase(newFriend))
{
System.out.println("Error: This friend already exists.");
positiveChecker = true;
}
}
if (positiveChecker == false)
{
FacebookUser friend = new FacebookUser(newFriend, newFriend );
recommendedFriends.add(friend);
System.out.println(friend + " is now your friend.");
}
positiveChecker = false;
}
void defriend(String formerFriend)
{
boolean positiveChecker = false;
for (int i = 0; i < recommendedFriends.size(); i++)
{
if (recommendedFriends.get(i).toString().equalsIgnoreCase(formerFriend))
{
recommendedFriends.remove(i);
System.out.println(formerFriend + " has been removed from your friends list.");
positiveChecker = true;
}
if (recommendedFriends.size() == (i + 1) && recommendedFriends.get(i).toString() != formerFriend
&& positiveChecker == false)
{
System.out.println("Error: There is no friend with this username.");
}
}
positiveChecker = false;
}
public interface Command
{
public void undo();
public void redo();
}
您误解了命令模式的工作原理。您想要 Commands
的单独 List
,其中每个 Command 实例代表一个 action。
所以你会想要这样的东西:
List<Command> actionStack;
然后有像
这样的东西public class AddCommand implements Command {
private final void List<FacebookUser> userList;
private final void FacebookUser newUser;
public AddCommand(List<FacebookUser> userList, FacebookUser newUser) {
this.userList = userList;
this.newUser = newUser;
}
@Override
public void undo() {
userList.remove(newUser);
}
@Override
public void redo() {
userList.add(newUser);
}
}
当你撤消 2 件事然后做一个全新的动作时,你需要 "forget" "redo history" 并用新命令替换它,对吗?
例如...
- 加好友吉姆
- 添加好友账单
- 加好友吉尔
- 删除吉姆
- 撤消
- 撤消
状态应为 "Jim" 和 "Bill"。
所以你真的只需要一个列表和一个指向当前 "command" 的指针,例如...
// Note: NOT thread safe!
public class CommandStack {
private List<Command> commands = Collections.emptyList();
private int nextPointer = 0;
public void doCommand(Command command) {
List<Command> newList = new ArrayList<>(nextPointer + 1)
for(int k = 0; k < nextPointer; k++) {
newList.add(commands.get(k));
}
newList.add(command);
commands = newList;
nextPointer++;
// Do the command here, or return it to whatever called this to be done, or maybe it has already been done by now or something
// (I can only guess on what your code currently looks like...)
command.execute();
}
public boolean canUndo() {
return nextPointer > 0;
}
public void undo() {
if(canUndo()) {
nextPointer--;
Command commandToUndo = commands.get(nextPointer);
// Undo the command, or return it to whatever called this to be undone, or something
command.undo();
} else {
throw new IllegalStateExcpetion("Cannot undo");
}
}
public boolean canRedo() {
return nextPointer < commands.size();
}
public void redo() {
if(canRedo()) {
commandToDo = commands.get(nextPointer);
nextPointer++;
// Do the command, or return it to whatever called this to be re-done, or something
commandToDo.execute();
} else {
throw new IllegalStateException("Cannot redo");
}
}
}
如果我有...
interface Command { /* execute / undo etc */ }
public class AddFriendCommand implements Command {
private String friendName;
// ... other fields, constructor / getters etc ...
public void execute() {
// Actually do it...
System.out.println("Added friend " + name);
}
public void undo() {
// Undo it...
System.out.println("Removed friend " + name);
}
}
public class RemoveFriendCommand implements Command {
private String friendName;
// ... other fields, constructor / getters etc ...
public void execute() {
// Actually do it, maybe throw exception if friend does not exist?
// (that would have to be a runtime exception unless you want the interface's method to throw stuff);
System.out.println("Removed friend " + name);
}
public void undo() {
// Undo it...
System.out.println("Added friend " + name);
}
}
您可以使用...重复上述序列
CommandStack stack = new CommandStack();
stack.doCommand(new AddFriendCommand("Jim"));
stack.doCommand(new AddFriendCommand("Bill"));
stack.doCommand(new AddFriendCommand("Jill"));
stack.doCommand(new RemoveFreindCommand("Jim"));
stack.undo();
stack.undo();
如果您现在执行了一个新命令(通过 doCommand),它会忘记您曾经添加过 "Jill" 或删除过 "Jim",而是现在会记住新命令和命令的其余部分无法撤销的历史。
希望对您有所帮助。