开发者

Implements undoable command - Java

开发者 https://www.devze.com 2023-03-21 05:55 出处:网络
I\'m currently programming a little text editor (project for school) and I\'m having some troubles finding a good and clean way to manage the undoable commands.

I'm currently programming a little text editor (project for school) and I'm having some troubles finding a good and clean way to manage the undoable commands.

(It is not a code review question as it's not only about improvement. I need to change my code if I want my application to work as I want it to)

Here's how my application works: I have a concrete subject that holds the buffer that is actually an arraylist of characters. Whenever this arraylist is modified (insertion, cut, paste...), the subject updates the observers - which consist in only one gui for the moment - (MVC pattern).

What I was doing until now for the undo and redo 开发者_开发技巧was saving the whole state of the buffer (through a memento), which is working fine but:

  • could obviously be improved.
  • is not working for the new feature that I need to implement (recording user actions so he can play them back whenever he wants to)

I can't figure out how to save the commands instead of the buffer, and if it is the good way to go.

Here's some chunks of the program (for the insert command):

"GUI".java

...

class KeyboardListener extends KeyAdapter { 

    @Override
    public void keyPressed(KeyEvent e) {
            ...
            commandManager.executeCommandInsert(caretStart, caretStop, e.getKeyChar());
            ...
    }
    ...
}

CommandManager.java

...

public void executeCommandInsert(int start, int end, char character) {  
    addMementoUndo();   
    commandInsert.setCarets(start, end);
    commandInsert.setChar(character);
    commandInsert.execute();    
}

public void addMementoUndo() 
{
    TextConcrete text = TextConcrete.getInstance();
    this.commandsUndo.add(0, text.createMemento());
    if(recordMode){
        this.recordings.add(text.createMemento());
    }
}
...

CommandInsert.java

...
public void execute(){
   TextConcrete text = TextConcrete.getInstance();
   text.insert(this.start, this.end, this.character);
}
...

TextConcrete.java

...
public void insert(int start, int end, char character){
    //inserting in ArrayList
}

public CommandUndoable createMemento(){
   CommandUndoable mem = new CommandUndoable();
   mem.setState(getState());
   return mem;
}

public String getState(){
   StringBuilder temp = new StringBuilder();
   for(int idx = 0; idx < this.state.size(); idx++){
       temp.append(this.state.get(idx));
   }    
   return temp.toString();
}
...

The CommandUndoable is just the memento that save the state of the buffer and then is saved in a list of memento in the CareTaker (CommandManager).

Any help would really be appreciated.


You could create a Undoable interface that commands can implement such as:

public interface Undoable {

   public void do(Editor text)

   public void undo(Editor text)

}

where Editor is the model of your editor that you can insert text into, remove text from, or manipulate with other commands. A command implementing the interface only needs to know how to 'do' and 'undo' itself, so you do not need to store a copy of the text buffer at each step, just store a List of the commands.


I would prefer to define two interfaces, but without any arguments in their methods

public interface Command {

    public void execute();

}

... and for Undo Actions:

 public interface UndoableCommand extends Command  {

    public void undo();

}

I think, this is more flexible, because you may have some interactions in your application that are not Undoable. (Like saving or loading a file)

To implement such a UndoableCommand just write somethink like that..

 public class EditorInsertCommand implements UndoableCommand  {

    private Editor editor;

    private String textToInsert;

    private String textBefore;

    public EditorInsertCommand(Editor editor, String textToInsert){
       this.editor = editor;
       this.textToInsert = textToInsert;
    }


    public void execute() {
        this.textBefore = editor.getText();
        editor.setText(textToInsert);
    };

    public void undo(){
       editor.setText(textBefore );
    };

}

The handling of execute and undo, can be done via a CommandManager as well.

0

精彩评论

暂无评论...
验证码 换一张
取 消