淺談Command命令模式

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模式,迭代器模式等做爲輔助,另外在生成對象的時候還可能使用原型模式,在保存命令的時候還可能使用備忘錄模式。本例是一個很好的例子,在本質上說明了命令模式就是將命令抽象成一個類,經過保存接收者的引用,在後期還可讓接收者去執行,一樣的使用了組合模式將這些對象一個個的保存下來,而後一步步的調用單個命令的執行方法,該執行方法經過命令的接收者去再次執行命令,這種方式特別的方便,由於咱們保存的是用戶的操做,可以一直記錄下來,甚至能夠保存到文件後恢復,由此能夠看到命令模式的強大。

 

淺談設計模式<最通俗易懂的講解>

相關文章
相關標籤/搜索