1、前言java
命令也是類,將命令做爲一個類來保存,當要使用的時候能夠直接拿來使用,好比腳本語言寫出的腳本,只須要一個命令就能執行獲得咱們想要的須要操做很長時間才能獲得的結果。這是一個很是有意思的模式,將操做的步驟保存下來,本例之中咱們使用java自帶的GUI來畫圖,而後將畫圖的過程(在哪一個地方畫了什麼東西)保存下來,能夠把每一次咱們的操做做爲一個命令,其實就是<使用什麼畫布,畫點的座標>,將這個命令對應的對象保存到全部命令對象的集合之中去,這樣命令集合就記錄下來了每個命令,若是要顯示畫的內容的時候,直接將這些命令組合讀取出來在進行一次重畫便可。經過這種模式保存下來已經執行的步驟,經過重畫再複述出來,是一種很是重要的開發理念,在須要保存歷史紀錄並恢復的場合是很是有用的。編程
2、代碼canvas
Command接口:設計模式
1 package zyr.dp.command; 2 3 public interface Command { 4 public abstract void execute(); 5 }
DrawCommand類:app
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接口:dom
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類:ide
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 }
實驗結果:函數
由此咱們能夠看到保存了的命令就這樣一個個的再次執行了一遍,是否是頗有意思呢?!this
讓咱們分析一下程序執行的過程:spa
一、開始執行初始化界面,而後顯示:
1 public static void main(String[] args) { 2 3 new Main("命令模式"); 4 5 }
1 public Main(String title){ 2 super(title); 3 4 this.addWindowListener(this); 5 canvas.addMouseMotionListener(this); 6 btnClear.addActionListener(this); 7 btnRePaint.addActionListener(this); 8 9 Box btnBox=new Box(BoxLayout.X_AXIS); 10 btnBox.add(btnClear); 11 btnBox.add(btnRePaint); 12 13 Box mainBox=new Box(BoxLayout.Y_AXIS); 14 mainBox.add(btnBox); 15 mainBox.add(canvas); 16 17 getContentPane().add(mainBox); 18 19 pack(); 20 show(); 21 }
二、而後等待用戶的操做,當監聽到用戶在界面上拖動鼠標的時候,執行:
1 @Override 2 public void mouseDragged(MouseEvent e) { 3 Command cmd=new DrawCommand(canvas,e.getPoint()); 4 history.append(cmd); 5 cmd.execute(); 6 }
三、建立一個命令對象,而後記錄進命令堆棧之中,以後咱們跟蹤 cmd.execute();
1 package zyr.dp.command; 2 3 public interface Command { 4 public abstract void execute(); 5 }
四、這裏就看到咱們的面向抽象編程的好處了,根本不須要知道是誰執行了咱們的命令,在命令的時候天然知道了,那就是new DrawCommand(canvas,e.getPoint());咱們繼續跟蹤:
1 public class DrawCommand implements Command { 2 3 。。。 4 public void execute() { 5 drawable.draw(position.x, position.y); 6 } 7 8 }
五、繼續跟蹤:
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模式,迭代器等模式做爲輔助,另外在生成對象的時候還可能使用原型模式,在保存命令的時候還可能使用備忘錄模式。本例是一個很好的例子,從本質上說明了命令模式就是將命令抽象成一個類,經過保存接收者的引用,在後期還可讓接收者去執行,一樣的使用了組合模式將這些對象一個個的保存了下來,而後一步步的調用單個命令的執行方法,該執行方法通知命令的接收者去再次執行命令,這種方式特別的方便,由於咱們保存的是用戶的操做,可以一直記錄下來,甚至能夠保存到文件之中之後能夠恢復,由此能夠看到命令模式的強大。