设计模式:命令(Command)模式
一、前言
命令也是类,将命令作为一个类来保存,当要使用的时候可以直接拿来使用,比如脚本语言写出的脚本,只需要一个命令就能执行得到我们想要的需要操作很长时间才能得到的结果。这是一个非常有意思的模式,将操作的步骤保存下来,本例之中我们使用java自带的GUI来画图,然后将画图的过程(在哪个地方画了什么东西)保存下来,可以把每一次我们的操作作为一个命令,其实就是<使用什么画布,画点的坐标>,将这个命令对应的对象保存到所有命令对象的集合之中去,这样命令集合就记录下来了每一个命令,如果要显示画的内容的时候,直接将这些命令组合读取出来在进行一次重画即可。通过这种模式保存下来已经执行的步骤,通过重画再复述出来,是一种非常重要的开发理念,在需要保存历史纪录并恢复的场合是非常有用的。
二、代码
Command接口:
1 package zyr.dp.command; 2 3 public interface Command { 4 public abstract void execute(); 5 }
DrawCommand类:
1 package zyr.dp.command; 2 3 import java.awt.Point; 4 5 6 public class DrawCommand implements Command { 7 8 private Drawable drawable; 9 private Point position; 10 public DrawCommand(Drawable drawable,Point position){ 11 this.drawable=drawable; 12 this.position=position; 13 } 14 15 public void execute() { 16 drawable.draw(position.x, position.y); 17 } 18 19 }
MacroCommand 类:
1 package zyr.dp.command; 2 3 import java.util.Iterator; 4 import java.util.Stack; 5 6 public class MacroCommand implements Command { 7 8 Stack commands=new Stack(); 9 10 public void execute() { 11 Iterator it = commands.iterator(); 12 while(it.hasNext()){ 13 Command command=(Command)it.next(); 14 command.execute(); 15 } 16 } 17 18 public void append(Command command){ 19 if(command!=this){ 20 commands.add(command); 21 } 22 } 23 24 public void clear(){ 25 commands.clear(); 26 } 27 28 public void undo(){ 29 if(!commands.isEmpty()){ 30 commands.pop(); 31 } 32 } 33 34 }
Drawable接口:
1 package zyr.dp.command; 2 3 public interface Drawable { 4 5 public abstract void draw(int x,int y); 6 7 }
DrawCanvas 实现类:
1 package zyr.dp.command; 2 3 import java.awt.*; 4 import java.util.Random; 5 6 7 public class DrawCanvas extends Canvas implements Drawable { 8 9 private static final long serialVersionUID = 1972130370393242746L; 10 11 private MacroCommand history; 12 private int radius=8; 13 14 public DrawCanvas(int width,int hieght, MacroCommand history){ 15 setSize(width,hieght); 16 setBackground(Color.white); 17 this.history=history; 18 } 19 20 public void draw(int x, int y) { 21 Random random = new Random(); 22 23 Graphics g = getGraphics(); 24 g.setColor((random.nextBoolean())? Color.yellow : Color.MAGENTA); 25 g.fillOval(x-radius, y-radius, radius*2, radius*2); 26 } 27 28 @Override 29 public void paint(Graphics g) { 30 System.out.println("执行一次刷新!"+System.currentTimeMillis()); 31 history.execute(); 32 } 33 34 }
Main类:
1 package zyr.dp.command; 2 3 import java.awt.event.ActionEvent; 4 import java.awt.event.ActionListener; 5 import java.awt.event.MouseEvent; 6 import java.awt.event.MouseMotionListener; 7 import java.awt.event.WindowEvent; 8 import java.awt.event.WindowListener; 9 10 import javax.swing.*; 11 12 13 public class Main extends JFrame implements ActionListener,MouseMotionListener,WindowListener{ 14 15 private MacroCommand history=new MacroCommand() ; 16 17 private JButton btnClear=new JButton("清除"); 18 private JButton btnRePaint=new JButton("重现"); 19 20 private DrawCanvas canvas=new DrawCanvas(400,400,history); 21 22 public Main(String title){ 23 super(title); 24 25 this.addWindowListener(this); 26 canvas.addMouseMotionListener(this); 27 btnClear.addActionListener(this); 28 btnRePaint.addActionListener(this); 29 30 Box btnBox=new Box(BoxLayout.X_AXIS); 31 btnBox.add(btnClear); 32 btnBox.add(btnRePaint); 33 34 Box mainBox=new Box(BoxLayout.Y_AXIS); 35 mainBox.add(btnBox); 36 mainBox.add(canvas); 37 38 getContentPane().add(mainBox); 39 40 pack(); 41 show(); 42 } 43 44 public static void main(String[] args) { 45 46 new Main("命令模式"); 47 48 } 49 50 51 @Override 52 public void actionPerformed(ActionEvent e) { 53 if(e.getSource()==btnClear){ 54 history.clear(); 55 canvas.repaint(); 56 }else if(e.getSource()==btnRePaint){ 57 canvas.repaint(); 58 } 59 } 60 61 62 @Override 63 public void mouseDragged(MouseEvent e) { 64 Command cmd=new DrawCommand(canvas,e.getPoint()); 65 history.append(cmd); 66 cmd.execute(); 67 } 68 69 @Override 70 public void windowClosing(WindowEvent e) { 71 System.exit(0); 72 } 73 74 75 76 77 @Override 78 public void windowOpened(WindowEvent e) { 79 } 80 81 @Override 82 public void windowClosed(WindowEvent e) { 83 } 84 85 @Override 86 public void windowIconified(WindowEvent e) { 87 } 88 89 @Override 90 public void windowDeiconified(WindowEvent e) { 91 } 92 93 @Override 94 public void windowActivated(WindowEvent e) { 95 } 96 97 @Override 98 public void windowDeactivated(WindowEvent e) { 99 } 100 101 @Override 102 public void mouseMoved(MouseEvent e) { 103 } 104 }
实验结果:
由此我们可以看到保存了的命令就这样一个个的再次执行了一遍,是不是很有意思呢?!
三、总结
对于命令模式,在本例之中使用了Composite模式,迭代器等模式作为辅助,另外在生成对象的时候还可能使用原型模式,在保存命令的时候还可能使用备忘录模式。本例是一个很好的例子,从本质上说明了命令模式就是将命令抽象成一个类,通过保存接收者的引用,在后期还可以让接收者去执行,同样的使用了组合模式将这些对象一个个的保存了下来,然后一步步的调用单个命令的执行方法,该执行方法通知命令的接收者去再次执行命令,这种方式特别的方便,因为我们保存的是用户的操作,能够一直记录下来,甚至可以保存到文件之中以后可以恢复,由此可以看到命令模式的强大。
原文地址:https://www.cnblogs.com/zyrblog/p/9252664.html