设计模式(二十二)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 ...
随机推荐
- 数据结构之二叉树篇卷二 -- 二叉树递归遍历(With Java)
一.先序递归遍历(Preorder Recursive Traversal) 1.1 算法 首先需要明确的是这里的序是针对 root 节点而言的.故先序即先“访问”根节点,其次“访问”其左右节点. 1 ...
- selenium-03-01截图函数
UI自动化测试执行过程中,当遇到检查失败的情况,往往会发现打印的log并不能有效地帮助我们定位问题.我们需要失败时刻的屏幕截图来重现当时的失败场景,进而排查出错原因. 基于这种需求可以使用Sele ...
- Apache Thrift 的基本使用
Apache Thrift 的基本使用 可以先看看官网是如何介绍的 The Apache Thrift software framework, for scalable cross-language ...
- Spring boot 官网学习笔记 - Spring Boot CLI 入门案例
安装CLI https://repo.spring.io/release/org/springframework/boot/spring-boot-cli/2.1.1.RELEASE/spring-b ...
- Maven 梳理 - 使用Maven构建多模块项目
多模块实际案例 project |--business (核心业务) |--business-api |--business-service |--business-message |--busine ...
- Base64编码有时会默认换行 [转]
Base64编码有时会默认换行 2013-01-27 20:59 6647人阅读 评论(0) 收藏 举报 分类: Base64 换行 版权声明:本文为博主原创文章,未经博主允许不得转载. ...
- ARP攻击原理简析及防御措施
0x1 简介 网络欺骗攻击作为一种非常专业化的攻击手段,给网络安全管理者,带来严峻的考验.网络安全的战场已经从互联网蔓延到用户内部的网络, 特别是局域网.目前利用ARP欺骗的木马病毒在局域网中广泛传 ...
- 【maven的使用】1maven的概念与配置
maven是一个基于java平台的自动化构建工具.构建工具的发展由make->ant->maven->gradle其中gradle还在发展中,使用较少,学习难度比较大,所以目前占据主 ...
- IoC 之加载 Bean:总结
上文中我们将bean已经加载到了IOC容器中,接下来我们将把IOC加载Bean出来进行代码解析 备注:(有些解释是参考别个博客的相关解释 )一起探讨请加我QQ:1051980588 bean 的初始化 ...
- Head First设计模式——策略模式
1.继承带来的扩展和复用问题 继承作为面向对象的三大要素(封装.继承.多态)之一为什么会带来问题,问题如何解决然后形成一种设计模式,head frist设计模式书中以鸭子作为例子讲解什么情况下继承的方 ...