实现可撤消命令 - Java

发布于 2024-11-24 23:32:36 字数 2058 浏览 0 评论 0原文

我目前正在编写一个小型文本编辑器(学校项目),并且在寻找一种良好且干净的方法来管理可撤消命令时遇到了一些麻烦。

(这不是一个代码审查问题,因为它不仅涉及改进。如果我希望我的应用程序按我希望的方式工作,我需要更改我的代码)

这是我的应用程序的工作原理:我有一个具体的主题,它保存了缓冲区实际上是一个字符数组列表。每当这个数组列表被修改(插入、剪切、粘贴...)时,主体就会更新观察者 - 目前仅包含一个 gui - (MVC 模式)。

到目前为止,我所做的撤消和重做是保存缓冲区的整个状态(通过备忘录),这工作正常,但是:

  • 显然可以改进。
  • 不适用于我需要实现的新功能(记录用户操作,以便他可以随时播放它们)

我不知道如何保存命令而不是缓冲区,以及这是否是好方法去。

下面是程序的一些块(用于插入命令):

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

CommandUndoable 只是保存缓冲区状态的备忘录,然后保存在 CareTaker(CommandManager)中的备忘录列表中。

任何帮助将不胜感激。

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

远山浅 2024-12-01 23:32:36

您可以创建一个命令可以实现的可撤消接口,例如:

public interface Undoable {

   public void do(Editor text)

   public void undo(Editor text)

}

其中Editor是编辑器的模型,您可以在其中插入文本、从中删除文本或与其他编辑器一起操作命令。实现该接口的命令只需要知道如何“执行”和“撤消”本身,因此您不需要在每一步存储文本缓冲区的副本,只需存储文本缓冲区的列表命令。

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.

诠释孤独 2024-12-01 23:32:36

我更愿意定义两个接口,但在它们的方法中没有任何参数

public interface Command {

    public void execute();

}

......对于撤消操作:

 public interface UndoableCommand extends Command  {

    public void undo();

}

我认为,这更灵活,因为您的应用程序中可能有一些不可撤消的交互。 (就像保存或加载文件一样)

要实现这样的UndoableCommand,只需编写类似的代码。

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

}

executeundo的处理可以是也通过 CommandManager 完成。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文