Использование шаблона Command для отмены и повтора в ArrayLists

Итак, у меня есть программа, в которой вы можете войти и добавить / удалить друзей в и из friends ArrayList. Также мне может понравиться определенная вещь, и эта вещь будет сохранена в likes ArrayList. Меня просят сделать варианты отмены и повтора для любого действия, которое я делаю.

Поэтому я хочу добавить яблоко в друзья. После этого, когда я выберу вариант отмены, я могу отменить это действие, чтобы яблоко не стало моим другом. Как я могу подойти к этому с Command Pattern когда вводится любое имя или слово, которое я ввел, чтобы сохранить в friends ArrayList?

Я провел небольшое исследование и обнаружил, что лучше всего использовать командную комбинацию, поскольку это должно быть сделано в рамках класса 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();
    }

2 ответа

Решение

Когда вы отменяете две вещи, а затем совершаете совершенно новое действие, вам нужно "забыть" "историю повторов" и заменить ее новой командой, верно?

Например...

  1. Добавить друга Джима
  2. Добавить друга Билла
  3. Добавить друга Джилл
  4. Удалить Джима
  5. расстегивать
  6. расстегивать

Государство должно быть "Джим" и "Билл".

Так что вам нужен только один список и указатель на текущую "команду", например...

// 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", но вместо этого теперь запоминала бы новую команду и остальную часть истории команд, которая не была отменена.

Надеюсь это поможет.

Вы неправильно понимаете, как работает шаблон команды. Вы хотите иметь отдельный List вашей Commandsгде каждый экземпляр 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);
    }
}
Другие вопросы по тегам