ctrl+z的JAVA实现,借助了命令模式(command pattern)

前些天学习<<JAVA与模式>>,到命令模式时,随带给了一个CTRL+Z案例的实现,想来学习编程这么久,CTRL+Z还没有认真实现过。

因此,借助JAVA与模式里面的源代码,自己对撤销和回退进行了实现(JAVA与模式书中代码有部分问题)。此次用到了命令模式,因为有界面,有按钮,有接收者,有发送者。

以下是类图,只为方便,未考虑UML细节规范。

以下是程序的实现。

MainFrame类:提供Main方法,Client类:类似于看电视的人,这里关联了UndoableTextArea,ItsukyuQuatation是因为要初始化该对象

package undoRedo;

import java.awt.Frame;
import java.awt.event.*;

public class MainFrame extends Frame {

    private static UndoableTextArea text;
    private static ItsukyuQuatation panel;

    public MainFrame(String title)
    {
        super(title);
    }

    public static void main(String[] args)
    {

        //构造可撤消的textArea
        text = new UndoableTextArea("Your text here");
        //构造panel
        panel = new ItsukyuQuatation(text);
        //构造frame
        MainFrame frame = new MainFrame("测试undo和redo");
        //增加窗体关闭事件
        frame.addWindowListener(new WindowAdapter()
        {
            public void windowClosing(WindowEvent e)
            {
                System.exit(0);
            }
        });
        frame.add(panel);
        frame.setSize(300,300);
        frame.setVisible(true);
    }
}

ItsukyuQuatation类:面板类,里面包括undo和redo两个按钮,类似于命令模式中的摇控器。实现了ActionListener接口。

package undoRedo;

import java.awt.BorderLayout;
import java.awt.Panel;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

public class ItsukyuQuatation extends Panel implements ActionListener {

    private final Command undo;
    private final Command redo;

    public ItsukyuQuatation(UndoableTextArea text)
    {
        this.setLayout(new BorderLayout());
        Panel toolbar = new Panel();
        undo = new UndoCommand(text);
        redo = new RedoCommand(text);
        undo.addActionListener(this);
        redo.addActionListener(this);
        toolbar.add(undo);
        toolbar.add(redo);

        this.add(toolbar,"North");
        this.add(text,"Center");

    }

    public void actionPerformed(ActionEvent e) {
        // TODO Auto-generated method stub
        Command cmd = (Command)e.getSource();
        cmd.execute();
    }

}

UndoableTextArea类:类似于命令模式中的电视机类。实现了StateEditable接口,因此该类具有可撤销和重做的功能。重载的storeState和restoreState即是把文本中的内容放到hashTable里去。

该类是最核心的类,实现ctrl+z的原理简单说就是UndoManger.edits是一个Vector动态数组,对每次的按键动作,都会存储一份当前的文本内容到数据。当点击undo按钮,

数组索引(UnoManager类的indexOfNextAdd变量)前移一位,取得前一状态的文本内容。点击redo按钮,数组索引后移一位,取后一状态的文本内容。但是各状态内容均未删或修改。

initUndoable()方法,如果用keyPressed事件,那么最近的状态未加到undoManager.edits列里。因此选用keyReleased事件。如果监听valueChanged事件,那么代码就

和JAVA与模式一书中一样,只能实现最近一次的编辑撤消。

package undoRedo;

import java.awt.TextArea;
import java.awt.event.*;
import java.util.Hashtable;
import javax.swing.undo.*;

import javax.swing.undo.StateEditable;

public class UndoableTextArea extends TextArea implements StateEditable {

    private UndoManager undoManager;
    private final static String KEY_STATE="UndoableTextAreaKey";
    private StateEdit currentEdit;
    boolean textChanged = false;

    public UndoableTextArea()
    {
        super();
        initUndoable();
    }
    public UndoableTextArea(String string)
    {
        super(string);
        initUndoable();
    }

    //存储状态
    public void storeState(Hashtable<Object, Object> hashTable) {
        // TODO Auto-generated method stub
        hashTable.put(KEY_STATE, this.getText());
    }

    //还原状态
    public void restoreState(Hashtable<?, ?> hashTable) {
        // TODO Auto-generated method stub
        Object data = hashTable.get(KEY_STATE);
        if(data!=null)
        {
            this.setText((String)data);
        }
    }

    //撤销方法
    public boolean undo()
    {
        try
        {
            undoManager.undo();
            System.out.println("undo=" + undoManager.toString());
            return true;
        }catch(CannotUndoException e)
        {
            System.out.println("Can‘t undo");
        }
        return false;
    }

    //重做方法
    public boolean redo()
    {
        try
        {
            undoManager.redo();
            System.out.println("redo=" + undoManager.toString());
            return true;
        }catch(CannotRedoException e)
        {
            System.out.println("Can‘t redo");
        }
        return false;
    }

    private void initUndoable()
    {
        this.undoManager = new UndoManager();

        this.currentEdit = new StateEdit(this);

        this.addKeyListener(new KeyAdapter()
        {
            /*
             *
             * 如果用keyPressed事件,那么最近的状态未加到undoManager.edits列里。
             * 因此选用keyReleased事件。
             *
            public void keyPressed(KeyEvent event)
            {
                if(event.isActionKey())
                {
                    //takeSnapshot();
                }else
                {
                    textChanged = true;
                    takeSnapshot();
                }
            }
            */
            public void keyReleased(KeyEvent event)
            {
                if(event.isActionKey())
                {
                    //takeSnapshot();
                }else
                {
                    textChanged = true;
                    takeSnapshot();
                }
            }
        });

        this.addFocusListener(new FocusAdapter()
        {
            public void focusLost(FocusEvent event)
            {
                //takeSnapshot();
            }
        });

    }

    private void takeSnapshot()
    {
        if(textChanged)
        {
            this.currentEdit.end();

            this.undoManager.addEdit(this.currentEdit);

            this.currentEdit = new StateEdit(this);

            System.out.println("takeSnapshot=" + undoManager.toString());

            textChanged = false;
        }
    }

}

Command抽象类:定义按钮,抽象方法 execute()

UndoCommand,RedoCommand均是Command类的实现,类似于命令模式中的具体按钮,调用接收者的方法进行实现。

package undoRedo;

import java.awt.Button;

public abstract class Command extends Button {

    public Command(String caption)
    {
        super(caption);
    }

    public abstract void execute();
}
package undoRedo;

public class UndoCommand extends Command {

    UndoableTextArea text;

    public UndoCommand(UndoableTextArea text)
    {
        super("Undo");
        this.text = text;
    }

    @Override
    public void execute() {
        // TODO Auto-generated method stub
        text.undo();
    }

}
package undoRedo;

public class RedoCommand extends Command {

    UndoableTextArea text;

    public RedoCommand(UndoableTextArea text)
    {
        super("Redo");
        this.text = text;
    }

    @Override
    public void execute() {
        // TODO Auto-generated method stub
        text.redo();
    }

}
时间: 2024-08-09 01:48:29

ctrl+z的JAVA实现,借助了命令模式(command pattern)的相关文章

设计模式 - 命令模式(command pattern) 撤销(undo) 具体解释

命令模式(command pattern) 撤销(undo) 详细解释 本文地址: http://blog.csdn.net/caroline_wendy 參考命令模式: http://blog.csdn.net/caroline_wendy/article/details/31379977 命令模式能够用于运行撤销(undo)操作. 详细方法: 1. 对象类中须要保存状态, 如level. package command; public class CeilingFan { String lo

设计模式 - 命令模式(command pattern) 具体解释

命令模式(command pattern) 详细解释 本文地址: http://blog.csdn.net/caroline_wendy 命令模式(command pattern) : 将请求封装成对象, 以便使用不同的请求\队列\日志来參数化其它对象. 命令模式也能够支持撤销操作. 简单的命令模式的实现: 1. 详细的类, 每个类都有特定的方法: /** * @time 2014年6月9日 */ package command; /** * @author C.L.Wang * */ publ

设计模式 - 命令模式(command pattern) 详解

命令模式(command pattern) 详解 本文地址: http://blog.csdn.net/caroline_wendy 命令模式: 将请求封装成对象, 以便使用不同的请求\队列\日志来参数化其他对象. 命令模式也支持可撤销操作. 命令模式: 调用者(Invoker); 命令(Command): 可执行方法(execute), 具体命令(Concrete Command); 接受者(Receiver): 调用命令(Set Command); 具体方法: 1. 具体对象. /** *

设计模式 - 命令模式(command pattern) 多命令 详解

命令模式(command pattern) 多命令 详解 本文地址: http://blog.csdn.net/caroline_wendy 参考命令模式: http://blog.csdn.net/caroline_wendy/article/details/31379977 具体步骤: 1. 多命令, 把未使用的命令, 初始化为空对象(NoCommand), 根据参数(slot), 选择输出命令. /** * @time 2014年6月16日 */ package command; /**

设计模式 - 命令模式(command pattern) 撤销(undo) 详解

命令模式(command pattern) 撤销(undo) 详解 本文地址: http://blog.csdn.net/caroline_wendy 参考命令模式: http://blog.csdn.net/caroline_wendy/article/details/31379977 命令模式可以用于执行撤销(undo)操作. 具体方法: 1. 对象类中需要保存状态, 如level. package command; public class CeilingFan { String loca

设计模式 - 命令模式(command pattern) 宏命令(macro command) 详解

命令模式(command pattern) 宏命令(macro command) 详解 本文地址: http://blog.csdn.net/caroline_wendy 参考: 命名模式(撤销): http://blog.csdn.net/caroline_wendy/article/details/31419101 命令模式可以执行宏命令(macro command), 即多个命令的组合操作. 具体方法:  1. 其余代码与命令(撤销)一致 2. 添加宏命令(macro command),

设计模式 - 命令模式(command pattern) 多命令 具体解释

命令模式(command pattern) 多命令 具体解释 本文地址: http://blog.csdn.net/caroline_wendy 參考命令模式: http://blog.csdn.net/caroline_wendy/article/details/31379977 具体步骤: 1. 多命令, 把未使用的命令, 初始化为空对象(NoCommand), 依据參数(slot), 选择输出命令. /** * @time 2014年6月16日 */ package command; /*

设计模式----行为型模式之命令模式(Command Pattern)

下面来自head first设计模式的命令模式一章节. 定义 将"请求"封装成对象,以便使用不同的请求.队列或者日志来参数化其他对象.命令模式也支持可撤销的操作. 类图 注: 1.Client:该类主要创建concreteCommand类,并设置其接收者Recevier; 2.Receiver:该类为接收者类,该类主要是负责接收命令,和执行命令; 3.Command:该类为 所有命令的抽象类或或接口,该类具备抽象方法execute/undo方法; 4.Invoker:该类为调用者,该调

设计模式之命令模式---Command Pattern

模式的定义 命令模式是一个高内聚的模式,定义如下: Encapsulate a request as an object,thereby letting you parameterize clients with different requests,queue or log requests,and support undoable operations 将一个请求封装成一个对象,从而让你使用不同的请求把客户端参数化,对请求排队或者记录日志,可以提供命令的撤销和恢复功能. 模式的使用场景 只要

用最简单的例子理解命令模式(Command Pattern)

假设想让遥控器控制电灯的开关.电视机的开关和切换,该如何做? 所有的开.关.切换都是遥控器发出的指令,把这些指令统一抽象成一个接口. public interface IControl { void Execute(); } 把电灯.电视机抽象成类. public class Tv { public void TurnOn() { Console.WriteLine("电视机打开了"); } public void TurnOff() { Console.WriteLine("