设计模式(二十二)Command模式
一个类在进行工作时会调用自己或者是其他类的方法,虽然调用结果会反映在对象的状态中,但并不会留下工作的历史记录。
这时,如果我们有一个类,用来表示“请进行这项工作”的“命令”就会方便很多。每一项想做的工作就不再是“方法的调用”这种动态处理了,而是一个表示命令的类的实例,即可以用“物”表示。要想管理工作的历史记录,只需管理这些实例的集合即可,而且还可以随时再次执行过去的命令,或是将多个过去的命令整合为一个新命令并执行。
Command有时也被称为时间。当发生点击鼠标、按下键盘按键等事件时,我们可以先将这些事件作成实例,然后按照发生顺序放入队列中。接着,再依次去处理它们。

示例程序要实现的功能是,用户拖动鼠标时程序会绘制出红色圆点,点击clear按钮后会清除所有的圆点。用户每拖动一次鼠标,应用程序都会为“在这个位置画一个点”这条命令生成一个DrawCommand类的实例。只要保存了这条命令,以后有需要时就可以重新绘制。
package bigjunoba.bjtu.command;
public interface Command {
public abstract void execute();
}
Command接口是表示“命令”的接口。作用就是“执行”什么东西。
package bigjunoba.bjtu.command; import java.util.Stack;
import java.util.Iterator; public class MacroCommand implements Command {
// 命令的集合
private Stack<Command> commands = new Stack<Command>();
// 执行
public void execute() {
Iterator<Command> it = commands.iterator();
while (it.hasNext()) {
((Command)it.next()).execute();
}
}
// 添加命令,同时防止不小心将自己(this)添加进去。
public void append(Command cmd) {
if (cmd != this) {
commands.push(cmd);
}
}
// 删除push方法添加的最后一条命令
public void undo() {
if (!commands.empty()) {
commands.pop();
}
}
// 删除所有命令
public void clear() {
commands.clear();
}
}
MacroCommand类表示“由多条命令整合成的命令”。该类实现了Command接口。commands字段是Stack类型的,它是保存了多个Command(即实现了Command接口的实例)的集合。
package bigjunoba.bjtu.drawer; import bigjunoba.bjtu.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);
}
}
DrawCommand类实现了Command接口,表示“绘制一个点的命令”。构造函数的作用是生成“在这个位置绘制点”的命令。execute方法的作用是执行命令。
package bigjunoba.bjtu.drawer;
public interface Drawable {
public abstract void draw(int x, int y);
}
Drawable接口是表示“绘制对象”的接口。draw方法是用于绘制的方法。
package bigjunoba.bjtu.drawer; import bigjunoba.bjtu.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); //画圆点
}
}
history字段中保存的是DrawCanvas类自己应当执行的绘制命令的集合。该字段是Command.MacroCommand类型的。当需要重新绘制DrawCanvas是,java处理会调用paint方法。它所做的事情仅仅是调用了history.excute方法。这样,记录在history中的所有历史命令都会被重新执行一遍。
package bigjunoba.bjtu.test; import bigjunoba.bjtu.command.*;
import bigjunoba.bjtu.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");
}
}
Main类实现了mouseDragged方法,当鼠标被拖动时,会生成一条“在这个位置画点”的命令,Command cmd = new DrawCommand(canvas, e.getPoint());该命令会先被添加至绘制历史记录中,history.append(cmd);然后立即执行,cmd.execute();。

测试结果如上图所示。

示例程序的时序图。

Command模式的类图。
设计模式(二十二)Command模式的更多相关文章
- Java设计模式(十二) 策略模式
原创文章,同步发自作者个人博客,http://www.jasongj.com/design_pattern/strategy/ 策略模式介绍 策略模式定义 策略模式(Strategy Pattern) ...
- 备忘录模式 Memento 快照模式 标记Token模式 行为型 设计模式(二十二)
备忘录模式 Memento 沿着脚印,走过你来时的路,回到原点. 苦海翻起爱恨 在世间难逃避命运 相亲竟不可接近 或我应该相信是缘份 一首<一生所爱>触动了多少 ...
- 桥接模式 桥梁模式 bridge 结构型 设计模式(十二)
桥接模式Bridge Bridge 意为桥梁,桥接模式的作用就像桥梁一样,用于把两件事物连接起来 意图 将抽象部分与他的实现部分进行分离,使得他们都可以独立的发展. 意图解析 依赖倒置原 ...
- Java 设计模式系列(二十)状态模式
Java 设计模式系列(二十)状态模式 状态模式,又称状态对象模式(Pattern of Objects for States),状态模式是对象的行为模式.状态模式允许一个对象在其内部状态改变的时候改 ...
- JAVA基础知识总结:一到二十二全部总结
>一: 一.软件开发的常识 1.什么是软件? 一系列按照特定顺序组织起来的计算机数据或者指令 常见的软件: 系统软件:Windows\Mac OS \Linux 应用软件:QQ,一系列的播放器( ...
- WCF技术剖析之二十二: 深入剖析WCF底层异常处理框架实现原理[中篇]
原文:WCF技术剖析之二十二: 深入剖析WCF底层异常处理框架实现原理[中篇] 在[上篇]中,我们分别站在消息交换和编程的角度介绍了SOAP Fault和FaultException异常.在服务执行过 ...
- VMware vSphere 服务器虚拟化之二十二桌面虚拟化之创建View Composer链接克隆的虚拟桌面池
VMware vSphere 服务器虚拟化之二十二桌面虚拟化之创建View Composer链接克隆的虚拟桌面池 在上一节我们创建了完整克隆的自动专有桌面池,在创建过程比较缓慢,这次我们将学习创建Vi ...
- Java设计模式(十) 备忘录模式 状态模式
(十九)备忘录模式 备忘录模式目的是保存一个对象的某个状态,在适当的时候恢复这个对象. class Memento{ private String value; public Memento(Stri ...
- Senparc.Weixin.MP SDK 微信公众平台开发教程(二十二):如何安装 Nuget(dll) 后使用项目源代码调试
最近碰到开发者问:我使用 nuget 安装了 Senparc.Weixin SDK,但是有一些已经封装好的过程想要调试,我又不想直接附加源代码项目,这样就没有办法同步更新了,我应该怎么办? 这其实是一 ...
- 学习笔记:CentOS7学习之二十二: 结构化命令case和for、while循环
目录 学习笔记:CentOS7学习之二十二: 结构化命令case和for.while循环 22.1 流程控制语句:case 22.2 循环语句 22.1.2 for-do-done 22.3 whil ...
随机推荐
- Eureka实战-2【构建Multi Zone Eureka Server】
工程pom中公共依赖 <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEnco ...
- CSS3 box-shadow阴影
box-shadow: color x-offset v-offset blur spred color: 阴影的颜色 x-offset: 阴影水平距离; 0: 左右阴影平分:正值:阴影在对象的右侧: ...
- Kubernetes 系列(七):持久化存储StorageClass
前面的课程中我们学习了 PV 和 PVC 的使用方法,但是前面的 PV 都是静态的,什么意思?就是我要使用的一个 PVC 的话就必须手动去创建一个 PV,我们也说过这种方式在很大程度上并不能满足我们的 ...
- 开发电商平台用PHP语言和JAVA语言有什么区别?哪种语言更好?
现在很多行业都通过电子商务拓展业务,所以商城系统开发成为很多企业的刚性需求.一般有一点技术基础的客户应该知道目前商城系统开发主流语言有两个,PHP和Java.那么很多客户朋友会纠结是选择哪个语言开发好 ...
- c++ 对特定进程的内存监控
在工具实现的过程中,遇到了内存爆了的问题,部分模型的规模可以达到10的100次方方甚至1000次方.(工具的主要算法涉及到了递归,递归深度会很深,所以也用到了ulimit修改栈空间来缓解爆栈的问题,治 ...
- SpringBoot系列:Spring Boot使用模板引擎JSP
一.Java模板引擎 模板引擎(这里特指用于Web开发的模板引擎)是为了使用户界面与业务数据(内容)分离而产生的,它可以生成特定格式的文档,用于网站的模板引擎就会生成一个标准的HTML文档. 在jav ...
- JZOJ 3875 星球联盟
[问题描述] 在遥远的 S 星系中一共有 N 个星球,编号为 1…N.其中的一些星球决定组成联盟, 以方便相互间的交流. 但是,组成联盟的首要条件就是交通条件.初始时,在这 N 个星球间有 M 条太空 ...
- Java 操作Word表格——创建嵌套表格、添加/复制表格行或列、设置表格是否禁止跨页断行
本文将对如何在Java程序中操作Word表格作进一步介绍.操作要点包括 如何在Word中创建嵌套表格. 对已有表格添加行或者列 复制已有表格中的指定行或者列 对跨页的表格可设置是否禁止跨页断行 创建表 ...
- ubuntu下安装及配置git的方法
安装Git 一个全新的ubunt系统,需要安装Git(系统是不具有该工具的),方法如下: 在terminel中输入如下命令: sudo apt-get install git git-core git ...
- Redis实现分布式文件夹锁
缘起 最近做一个项目,类似某度云盘,另外附加定制功能,本人负责云盘相关功能实现,这个项目跟云盘不同的是,以项目为分配权限的单位,同一个项目及子目录所有有权限的用户可以同时操作所有文件,这样就很容易出现 ...