1、前言java
命令也是类,将命令做为一个类来保存,当要使用的时候能够直接拿来使用,好比脚本语言写出的脚本,只须要一个命令就能执行获得咱们想要的须要操做很长时间才能获得的结果。这是一个很是有意思的模式,将操做的步骤保存下来,本例中咱们使用java自带的GUI来画图,而后将画图的过程保存下来,能够把每一次咱们的操做做为一个命令,将这个命令对应的对象保存到全部命令对象的集合中去,这样命令集合就记录下来了每个命令,若是要显示画的内容的时候,直接将这些命令组合读取出来再进行一次重画便可。经过这种模式保存下来已经执行的步骤,经过重画再复述出来,是一种很是重要的开发理念,在须要保存历史记录并恢复的场合是很是有用的。编程
2、代码canvas
package designMode.Command; public interface Command { public abstract void excute(); }
package designMode.Command; import java.awt.*; public class DrawCommand implements Command { private Drawable drawable; private Point position; public DrawCommand(Drawable drawable, Point position) { this.drawable = drawable; this.position = position; } @Override public void excute() { drawable.draw(position.x,position.y); } }
package designMode.Command; import java.util.Iterator; import java.util.Stack; public class MacroCommand { Stack commands = new Stack(); public void execute(){ Iterator it = commands.iterator(); while (it.hasNext()){ Command command = (Command) it.next(); command.excute(); } } public void append(Command command){ if(command!=this){ commands.add(command); } } public void clear(){ commands.clear(); } public void undo(){ if(!commands.isEmpty()){ commands.pop(); } } }
package designMode.Command; public interface Drawable { public abstract void draw(int x,int y); }
package designMode.Command; import java.awt.*; import java.util.Random; public class DrawCanvas extends Canvas implements Drawable { private static final long serialVersionUID = 1972130370393242746L; private MacroCommand history; private int radius = 8; public DrawCanvas(int width,int height,MacroCommand history){ setSize(width,height); setBackground(Color.white); this.history = history; } @Override public void draw(int x, int y) { Random random = new Random(); Graphics g = getGraphics(); g.setColor((random.nextBoolean())? Color.yellow : Color.MAGENTA); g.fillOval(x-radius, y-radius, radius*2, radius*2); } public void paint(Graphics g){ System.out.println("执行一次刷新!"+System.currentTimeMillis()); history.execute(); } }
package designMode.Command; import javax.swing.*; import java.awt.event.*; public class Main extends JFrame implements ActionListener,MouseMotionListener,WindowListener { private MacroCommand history=new MacroCommand() ; private JButton btnClear=new JButton("清除"); private JButton btnRePaint=new JButton("重现"); private DrawCanvas canvas=new DrawCanvas(400,400,history); public Main(String title){ super(title); this.addWindowListener(this); canvas.addMouseMotionListener(this); btnClear.addActionListener(this); btnRePaint.addActionListener(this); Box btnBox=new Box(BoxLayout.X_AXIS); btnBox.add(btnClear); btnBox.add(btnRePaint); Box mainBox=new Box(BoxLayout.Y_AXIS); mainBox.add(btnBox); mainBox.add(canvas); getContentPane().add(mainBox); pack(); show(); } public static void main(String[] args) { new Main("命令模式"); } @Override public void actionPerformed(ActionEvent e) { if(e.getSource()==btnClear){ history.clear(); canvas.repaint(); }else if(e.getSource()==btnRePaint){ canvas.repaint(); } } @Override public void mouseDragged(MouseEvent e) { Command cmd=new DrawCommand(canvas,e.getPoint()); history.append(cmd); cmd.excute(); } @Override public void windowClosing(WindowEvent e) { System.exit(0); } @Override public void windowOpened(WindowEvent e) { } @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) { } @Override public void mouseMoved(MouseEvent e) { } }
由此咱们能够看到保存了的命令就这样一个个的再次执行了一遍,是否是颇有意思呢?!设计模式
让咱们分析一下程序执行的过程:app
一、开始执行初始化界面,而后显示:dom
public static void main(String[] args) { new Main("命令模式"); }
二、而后等待用户的操做,当监听到用户在界面上拖动鼠标的时候,执行:ide
@Override public void mouseDragged(MouseEvent e) { Command cmd=new DrawCommand(canvas,e.getPoint()); history.append(cmd); cmd.execute(); }
三、建立一个命令对象,而后记录进命令堆栈之中,以后咱们跟踪 cmd.execute();函数
package zyr.dp.command; public interface Command { public abstract void execute(); }
四、这里就看到咱们的面向抽象编程的好处了,根本不须要知道是谁执行了咱们的命令,在命令的时候天然知道了,那就是new DrawCommand(canvas,e.getPoint());咱们继续跟踪:this
public class DrawCommand implements Command { 。。。 public void execute() { drawable.draw(position.x, position.y); } }
五、继续跟踪:spa
1 package zyr.dp.command; 2 3 public interface Drawable { 4 5 public abstract void draw(int x,int y); 6 7 }
六、同理,谁实现了Drawable ,并被传递进去了,Command cmd=new DrawCommand(canvas,e.getPoint());
1 private DrawCanvas canvas=new DrawCanvas(400,400,history);
找到原主:DrawCanvas ,跟踪:
1 public void draw(int x, int y) { 2 Random random = new Random(); 3 4 Graphics g = getGraphics(); 5 g.setColor((random.nextBoolean())? Color.yellow : Color.MAGENTA); 6 g.fillOval(x-radius, y-radius, radius*2, radius*2); 7 } 8
所以执行咱们的程序,画了一个点。以后咱们的鼠标不断拖动着,这个流程就一直执行着,直到咱们中止为止。
以后咱们分析重画方法:
当用户点击按钮:
1 @Override 2 public void actionPerformed(ActionEvent e) { 3 if(e.getSource()==btnClear){ 4 history.clear(); 5 canvas.repaint(); 6 }else if(e.getSource()==btnRePaint){ 7 canvas.repaint(); 8 } 9 }
调用 canvas.repaint();方法,这是Canvas自动实现的,咱们没必要深究,只须要知道这个函数之中会调用,咱们的继承了Canvas而且重写的方法:
1 public void paint(Graphics g) { 2 System.out.println("执行一次刷新!"+System.currentTimeMillis()); 3 history.execute(); 4 }
跟踪: history.execute();
1 public void execute() { 2 Iterator it = commands.iterator(); 3 while(it.hasNext()){ 4 Command command=(Command)it.next(); 5 command.execute(); 6 } 7 }
能够看到将保存的命令一个个都拿出来,从新走了一遍咱们上面的command.execute();所走的流程,这就是命令模式,如今很清晰了。
3、总结
对于命令模式,在本例中使用了Composite模式,迭代器模式等做为辅助,另外在生成对象的时候还可能使用原型模式,在保存命令的时候还可能使用备忘录模式。本例是一个很好的例子,在本质上说明了命令模式就是将命令抽象成一个类,经过保存接收者的引用,在后期还可让接收者去执行,一样的使用了组合模式将这些对象一个个的保存下来,而后一步步的调用单个命令的执行方法,该执行方法经过命令的接收者去再次执行命令,这种方式特别的方便,由于咱们保存的是用户的操做,可以一直记录下来,甚至能够保存到文件后恢复,由此能够看到命令模式的强大。