命令模式(Command Pattern)是一种数据驱动的设计模式,它属于行为型模式。请求以命令的形式包裹在对象中,并传给调用对象。调用对象寻找可以处理该命令的合适的对象,并把该命令传给相应的对象,该对象执行命令。
Command.java
package com.test.dp.Command.Sample.command;
//表示命令的接口
public interface Command {
public abstract void execute();
}
MacroCommand.java
package com.test.dp.Command.Sample.command;
import java.util.Stack;
import java.util.Iterator;
//表示“由多条命令合成的命令”的类
public class MacroCommand implements Command {
// 命令的集合
private Stack commands = new Stack();
// 执行
public void execute() {
Iterator it = commands.iterator();
while (it.hasNext()) {
((Command)it.next()).execute();
}
}
// 添加命令
public void append(Command cmd) {
if (cmd != this) {
commands.push(cmd);
}
}
// 删除最后一条命令
public void undo() {
if (!commands.empty()) {
commands.pop();
}
}
// 删除所有命令
public void clear() {
commands.clear();
}
}
DrawCommand.java
package com.test.dp.Command.Sample.drawer;
import com.test.dp.Command.Sample.command.Command;
import java.awt.Point;
//表示“绘制一个点的命令”的类
public class DrawCommand implements Command {
// 绘制对象
protected Drawable drawable;
// 绘制位置
private Point position;
// 构造函数
public DrawCommand(Drawable drawable, Point position) {
this.drawable = drawable;
this.position = position;
}
// 执行
public void execute() {
drawable.draw(position.x, position.y);
}
}
Drawable.java
package com.test.dp.Command.Sample.drawer;
//表示“绘制对象”的接口
public interface Drawable {
public abstract void draw(int x, int y);
}
DrawCanvas.java
package com.test.dp.Command.Sample.drawer;
import com.test.dp.Command.Sample.command.*;
import java.util.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
//实现“绘制对象”的类
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) {
setSize(width, height);
setBackground(Color.white);
this.history = history;
}
// 重新全部绘制
public void paint(Graphics g) {
history.execute();
}
// 绘制
public void draw(int x, int y) {
Graphics g = getGraphics();
g.setColor(color);
g.fillOval(x - radius, y - radius, radius * 2, radius * 2);
}
}
Main.java
package com.test.dp.Command.Sample;
import com.test.dp.Command.Sample.command.*;
import com.test.dp.Command.Sample.drawer.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
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 title) {
super(title);
this.addWindowListener(this);
canvas.addMouseMotionListener(this);
clearButton.addActionListener(this);
Box buttonBox = new Box(BoxLayout.X_AXIS);
buttonBox.add(clearButton);
Box mainBox = new Box(BoxLayout.Y_AXIS);
mainBox.add(buttonBox);
mainBox.add(canvas);
getContentPane().add(mainBox);
pack();
show();
}
// ActionListener接口中的方法
public void actionPerformed(ActionEvent e) {
if (e.getSource() == clearButton) {
history.clear();
canvas.repaint();
}
}
// MouseMotionListener接口中的方法
public void mouseMoved(MouseEvent e) {
}
public void mouseDragged(MouseEvent e) {
Command cmd = new DrawCommand(canvas, e.getPoint());
history.append(cmd);
cmd.execute();
}
// WindowListener接口中的方法
public void windowClosing(WindowEvent e) {
System.exit(0);
}
public void windowActivated(WindowEvent e) {}
public void windowClosed(WindowEvent e) {}
public void windowDeactivated(WindowEvent e) {}
public void windowDeiconified(WindowEvent e) {}
public void windowIconified(WindowEvent e) {}
public void windowOpened(WindowEvent e) {}
public static void main(String[] args) {
new Main("Command Pattern Sample");
}
}
执行结果:
略
总结:
应用实例:struts 1 中的 action 核心控制器 ActionServlet 只有一个,相当于 Invoker,而模型层的类会随着不同的应用有不同的模型类,相当于具体的 Command。
优点:1、降低了系统耦合度。2、新的命令可以很容易添加到系统中去。
缺点:使用命令模式可能会导致某些系统有过多的具体命令类。
使用场景:认为是命令的地方都可以使用命令模式,比如:1、GUI 中每一个按钮都是一条命令。2、模拟 CMD。
注意事项:系统需要支持命令的撤销(Undo)操作和恢复(Redo)操作,也可以考虑使用命令模式,见命令模式的扩展。