Author:Gorit
Date:2021年11月28日
Refer:《图解设计模式》
22.1 Command 模式
一个类在进行工作时会调用自己 伙食 其他类的方法,虽然调用的结果会反映在对象的状态中,但并不会留下工作的历史记录
假如,有这样一个类,用来表示“请进行这项工作”的“命令”就会方便很多。每一项想做的工作就不再是“方法的调用”这种动态处理了,而是一个表示命令的类的实例,即可用“物”来表示,需要管理工作记录的历史记录。只需要管理这些实例的集合即可,还可以随时再次执行过去的命令,或是将多个过去的命令整合为一个新命令并执行
22.2 示例程序
我们将做一个绘图的程序,点击保存,可以实现绘制固定图形发的操作(因为保存了记录)
包 | 类 | 说明 |
---|---|---|
command | Command | 表示“命令”的接口 |
command | MacroCommand | 表示“由多条命令整合成的命令” |
drawer | DrawPointCommand | 表示“绘制一个点的命令” |
drawer | Drawable | 表示“绘制对象”的接口 |
drawer | DrawCanvas | 表示“绘制对象”的类 |
无 | Main | 测试程序行为 |
Command
package Commad.command;
/**
* @Author Gorit
* @Date 2021/11/28
* 执行操作
**/
public interface Command {
public abstract void execute();
}
MacroCommand
package Commad.command;
import java.util.Iterator;
import java.util.Stack;
/**
* @Author Gorit
* @Date 2021/11/28
**/
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();
}
}
DrawPointCommand
package Commad.drawer;
import Commad.command.Command;
import java.awt.*;
/**
* @Author Gorit
* @Date 2021/11/28
* 实现绘制一个点的功能
**/
public class DrawPointCommand implements Command {
// 绘制的对象
protected Drawable drawable;
// 绘制位置
private Point position;
public DrawPointCommand(Drawable drawable, Point position) {
this.drawable = drawable;
this.position = position;
}
public void execute() {
drawable.draw(position.x, position.y);
}
}
Drawable
package Commad.drawer;
/**
* @Author Gorit
* @Date 2021/11/28
* 提供绘制的接口
**/
public interface Drawable {
public abstract void draw(int x, int y);
}
DrawCanvas
package Commad.drawer;
import Commad.command.MacroCommand;
import java.awt.*;
/**
* @Author Gorit
* @Date 2021/11/28
**/
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 q) {
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
package Commad;
import Commad.command.Command;
import Commad.command.MacroCommand;
import Commad.drawer.DrawCanvas;
import Commad.drawer.DrawPointCommand;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
/**
* @Author Gorit
* @Date 2021/11/28
**/
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(buttonBox);
mainBox.add(canvas);
getContentPane().add(mainBox);
pack();
setVisible(true);
}
// ActionListener 中的方法
public void actionPerformed(ActionEvent e) {
if (e.getSource() == clearButton) {
history.clear();
canvas.repaint();
}
}
// MouseMotionListener 接口中的方法
public void mouseDragged(MouseEvent e) {
Command cmd = new DrawPointCommand(canvas, e.getPoint());
history.append(cmd);
cmd.execute();
}
public void mouseMoved(MouseEvent e) {}
// WindowListener 中的方法
public void windowOpened(WindowEvent e) {
}
public void windowClosing(WindowEvent e) {
System.exit(0);
}
public void windowClosed(WindowEvent e) {}
public void windowIconified(WindowEvent e) {}
public void windowDeiconified(WindowEvent e) {}
public void windowActivated(WindowEvent e) {}
public void windowDeactivated(WindowEvent e) {}
public static void main(String[] args) {
new Main("Command Simple");
}
}
22.3 Command 中登场的角色
一、Command(命令)
Command角色负责定义命令的接口(API)。在示例程序中,由 Command 接口扮演此角色
二、ConcreateCommand(具体的命令)
ConcreateCommand 角色负责实现在 Command 角色中定义的接口(API)。
由 MacroCommand 类 和 DrawCommand 类扮演此角色
三、Receiver(接受者)
Receiver 角色是 Command 角色执行命令时的对象,也可以成其为命令的接受者。
由 DrawCanvas 类 接收 DrawCommand 的命令。
四、Client(请求者)
Client 角色负责生成 ConcreateCommand 角色并分配 Receiver 角色。
由 Main 扮演此角色
鼠标响应拖拽事件时,它生成了 DrawCommand 类的实例,并将扮演 Receiver 角色的 DrawCanvas 类的实例传递给了 DrawCommand 类的构造函数
五、Invoker(发动者)
Invoke 角色是开始执行 命令的角色,它会调用 Command 角色中定义的接口(API)。在示例程序中,由 Main 类 和 DrawCanvas 类扮演此角色。这两个类都调用了 Command 接口中的 execute 方法。
Main 角色同时扮演了 Client 角色和 Invoker 角色
22.4 相关的设计模式
一、Composite 模式
有时会使用 Composite 模式实现宏命令
二、Memento 模式
有时会使用 Memento 模式来保存角色的历史记录
三、Protype 模式
有时会使用 Protype 模式复制发生的事件(生成的命令)