背景
如果我们有一个类,用来表示“请进行这项工作”的“命令”就会方便很多。每一项想做的工作就不再是“方法的调用”这种动态处理了,而是一个表示命令的类的实例,即可以用“物”来表示。
这样的“命令”称为 Command 模式
Command 有时也被称为事件,它与“事件驱动编程”中的“事件”是一样的意思。当发生点击鼠标、按下键盘按键等事件时,我们可以先将这些事件作成实例,然后按照发生顺序放入队列中。
登场角色
Command 命令
负责定义命令的API;
ConcreteCommand 具体的命令
实现Command 角色 中定义的 API;
Receiver 接收者
Receiver 角色 是 Command 角色执行命令时的对象,也可以称其为命令接收者。示例程序中由DrawCanvas 类接收 DrawCommand 命令;
Client 请求者
Client 角色负责生成 ConcreteCommand 角色 并分配 Receiver 角色
Invoker 发动者
Invoker 角色是开始执行命令的角色,他会调用在Command 角色中定义的接口(API),即调用Command 类中的 excute 方法
类图
示例代码
示例代码为一个绘图程序,用命令模式来记录以往的路径
Command
public interface Command {
void execute();
}
MacroCommand:记录命令的集合
public class MacroCommand implements Command {
private Stack<Command> commands = new Stack<>();
// 执行
@Override
public void execute() {
if (!commands.isEmpty()) {
Iterator<Command> it = commands.iterator();
while (it.hasNext()) {
Command command = it.next();
command.execute();
}
}
}
// 添加命令
public void addCommand(Command command) {
if (command != this)
commands.push(command);
}
// 撤销命令
public void undo() {
if (!commands.isEmpty()) {
commands.pop();
}
}
// 清除所有的命令
public void clear() {
commands.clear();
}
}
DrawCommand:具体的命令
public class DrawCommand implements Command {
protected Drawable drawable;
private Point position;
public DrawCommand(Drawable drawable, Point position) {
this.drawable = drawable;
this.position = position;
}
@Override
public void execute() {
drawable.draw(position.x, position.y);
}
}
Drawable:具体画图的接口
public interface Drawable {
void draw(int x, int y);
}
DrawCanvas:相当于Receiver
public class DrawCanvas extends Canvas implements Drawable{
private Color color = Color.red;
private int radius = 6;
// 保存历史记录
private MacroCommand history;
public DrawCanvas(int width, int heigth, MacroCommand history) {
setSize(width, heigth);
setBackground(Color.white);
this.history = history;
}
// 重绘历史记录
@Override
public void paint(Graphics g) {
history.execute();
}
// 绘制
@Override
public void draw(int x, int y) {
Graphics g = getGraphics();
g.setColor(color);
g.fillOval(x - radius, y - radius, radius * 2, radius * 2);
}
}
Main:启动类
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) throws HeadlessException {
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(clearButton);
mainBox.add(canvas);
getContentPane().add(mainBox);
pack();
show();
}
@Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == clearButton) {
history.clear();
canvas.repaint();
}
}
@Override
public void mouseDragged(MouseEvent e) {
Command command = new DrawCommand(canvas, e.getPoint());
history.addCommand(command);
command.execute();
}
@Override
public void mouseMoved(MouseEvent e) {
}
@Override
public void windowOpened(WindowEvent e) {
}
@Override
public void windowClosing(WindowEvent e) {
System.exit(0);
}
@Override
public void windowClosed(WindowEvent e) {
}
@Override
public void windowIconified(WindowEvent e) {
}
@Override
public void windowDeiconified(WindowEvent e) {
}
@Override
public void windowActivated(WindowEvent e) {
}
@Override
public void windowDeactivated(WindowEvent e) {
}
public static void main(String[] args) {
new Main("Command Pattern Sample");
}
}
功能分析
- 可以使用一个集合来保存历史命令,从而代表了记录历史记录;