一个类在进行工作时会调用自己或是其他类的方法,虽然调用结果会反映在对象的状态中,但是并不会留下工作的历史纪录。
这时,如果有一个类,用来表示进行这项工作的命令就会方便很多。每一项想做的工作就不再是方法的调用这种动态处理了,而是一个表示命令的类的实例,既可以用物来表示,要想管理工作的历史纪录,只需管理这些实例的集合即可,而且还可以随时再次执行过去的命令,或是将多个过去的命令整合为一个新命令并执行。
在设计模式中,我们称这样的命令为Command模式。
示例程序
这段示例程序是一个画图软件,用户拖动鼠标时程序会绘制出红色圆点,点击clear按钮后会清除所有圆点。
用户每拖动一次鼠标,应用程序都会为“在这个位置画一个点”这条命令生成一个DrawCommand类的实例,只要保存了这条实例,以后有需要时就可以重新绘制。
Command接口
该接口是表示命令的接口,它的作用就是执行什么东西。
package Command;
//命令接口
public interface Command {
//声明抽象方法
public abstract void execute();
}
MacroCommand类
该类表示由多条命令整个成的命令,该类实现了Command接口。
package Command;
import java.util.Iterator;
import java.util.Stack;
//实现Command接口,组织多条命令
public class MacroCommand implements Command {
private Stack<Command> commands = new Stack();
//执行压入命令栈中的每条命令,通过迭代器调用执行方法
@Override
public void execute() {
// TODO Auto-generated method stub
Iterator iterator = commands.iterator();
while(iterator.hasNext()){
((Command)iterator.next()).execute();
}
}
//如果有了新的命令,将新的命令压入栈中
public void append(Command cmd){
if(cmd!=this){
commands.push(cmd);
}
}
//如果撤回命令,则将命令对象pop出栈
public void undo(){
if(!commands.empty()){
commands.pop();
}
}
//栈清空
public void clear(){
commands.clear();
}
}
DrawCommand类
该类表示绘制一个点的命令,该类的两个字段一个保存的是绘制对象,另外一个保存的是绘制位置。
package Command;
import java.awt.Point;
//执行一条命令的类
public class DrawCommand implements Command {
//构造函数需要具体绘画类的实例和该对象在画布上的位置
protected Drawable drawable;
private Point position;
public DrawCommand(Drawable drawable,Point position) {
// TODO Auto-generated constructor stub
this.drawable = drawable;
this.position = position;
}
//执行绘制一个点的方法
@Override
public void execute() {
// TODO Auto-generated method stub
drawable.draw(position.x,position.y);
}
}
Drawable接口
该接口是表示绘制对象的接口。
package Command;
//绘制的接口
public interface Drawable {
public abstract void draw(int x,int y);
}
DrawCanvas类
该类实现了Drawable接口。
package Command;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Graphics;
//绘制画布和绘制点的类
public class DrawCanvas extends Canvas implements Drawable {
private Color color = Color.red;
private int radius = 6;
private MacroCommand history;
//构造函数绘制画布
public DrawCanvas(int width,int height,MacroCommand history) {
// TODO Auto-generated constructor stub
setSize(width,height);
setBackground(Color.white);
this.history = history;
}
//该方法绘制一个点,包括创建画笔实例,设置画笔颜色,以及最终的画圆
@Override
public void draw(int x, int y) {
// TODO Auto-generated method stub
Graphics graphics = getGraphics();
graphics.setColor(color);
graphics.fillOval(x-radius, y-radius, radius*2, radius*2);
}
//重新执行命令栈中的命令
public void paint(Graphics g){
history.execute();
}
}
Main类
package Command;
import java.awt.Canvas;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
public class Main extends JFrame implements ActionListener, MouseMotionListener, WindowListener {
//创建多命令链对象
private MacroCommand history = new MacroCommand();
//初始化画布
private DrawCanvas canvas = new DrawCanvas(400, 400, history);
//创建按钮对象
private JButton clearButton = new JButton("clear");
public Main(String string){
super(string);
//为空间添加事件监听
this.addWindowListener(this);
canvas.addMouseMotionListener(this);
clearButton.addActionListener(this);
//设置布局
Box buttonnBox = new Box(BoxLayout.X_AXIS);
buttonnBox.add(clearButton);
Box mainBox = new Box(BoxLayout.Y_AXIS);
mainBox.add(buttonnBox);
mainBox.add(canvas);
getContentPane().add(mainBox);
pack();
show();
}
@Override
public void windowOpened(WindowEvent e) {
// TODO Auto-generated method stub
}
@Override
public void windowClosing(WindowEvent e) {
// TODO Auto-generated method stub
System.exit(0);
}
@Override
public void windowClosed(WindowEvent e) {
// TODO Auto-generated method stub
}
@Override
public void windowIconified(WindowEvent e) {
// TODO Auto-generated method stub
}
@Override
public void windowDeiconified(WindowEvent e) {
// TODO Auto-generated method stub
}
@Override
public void windowActivated(WindowEvent e) {
// TODO Auto-generated method stub
}
@Override
public void windowDeactivated(WindowEvent e) {
// TODO Auto-generated method stub
}
//鼠标拖拽事件发生时,创建一条命令,将该命令加入栈中,执行命令
@Override
public void mouseDragged(MouseEvent e) {
// TODO Auto-generated method stub
Command cmd = new DrawCommand(canvas,e.getPoint());
history.append(cmd);
cmd.execute();
}
@Override
public void mouseMoved(MouseEvent e) {
// TODO Auto-generated method stub
}
@Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
//如果按下清除键,则清除历史栈中的命令,重新绘制画布
if(e.getSource() == clearButton){
history.clear();
canvas.repaint();
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
new Main("Command Pattern Sample");
}
}
Command模式类图
Command模式时序图