【问题标题】:Using Command pattern for undo and redo in ArrayLists在 ArrayLists 中使用命令模式进行撤消和重做
【发布时间】:2015-06-22 00:29:38
【问题描述】:

所以我有一个程序,您可以在其中登录并在friends 数组列表中添加/删除朋友。我也可以喜欢某个东西,那个东西将被存储到likes arraylist 中。我被要求为我执行的任何操作设置撤消和重做选项。

所以我想加 apple 为好友。之后,当我选择撤消选项时,我可以撤消该操作,这样 apple 就不再是我的朋友了。当输入是我输入要存储到friends 数组列表中的任何名称或单词时,我如何使用Command Pattern 来解决这个问题?

我做了一些研究,发现使用命令模式可能是我最好的选择,因为这必须在我已经拥有的 Facebook 类下完成。我假设我必须使用两个不同的堆栈,但我对这个话题有点迷失了。

我决定添加我所拥有的部分内容,以便在我需要做什么以及我的程序做什么方面获得更多帮助。

在驱动程序中

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 课堂中

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();
    }

【问题讨论】:

标签: java arraylist command-pattern


【解决方案1】:

当你撤消两件事然后执行一个全新的操作时,你需要“忘记”“重做历史”并用新命令替换它,对吧?

例如...

  1. 加好友吉姆
  2. 加好友比尔
  3. 加好友吉尔
  4. 删除吉姆
  5. 撤消
  6. 撤消

State 应该是“Jim”和“Bill”。

所以你只需要一个列表和一个指向当前“命令”的指针,例如...

// 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”,但现在会记住新命令和其他未撤消的命令历史记录。

希望这会有所帮助。

【讨论】:

  • 我添加了更多代码以使您更轻松。那么这是否意味着我必须创建一个新类并为命令接口使用指针?
【解决方案2】:

您误解了命令模式的工作原理。您希望有一个单独的 ListCommands,其中每个 Command 实例代表一个动作

所以你会想要这样的东西:

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);
    }
}

【讨论】:

  • 我仍然需要一些帮助。我可以给你我的代码让事情变得更简单吗?
  • @user2904667 随时编辑您的具体问题。不要只是转储所有代码。
  • 希望对您有所帮助。
猜你喜欢
  • 1970-01-01
  • 2011-03-16
  • 2016-11-18
  • 2013-09-30
  • 2011-11-22
  • 2011-06-14
  • 1970-01-01
  • 2013-01-17
  • 1970-01-01
相关资源
最近更新 更多