文档章节

浅谈Command命令模式

青衣霓裳
 青衣霓裳
发布于 10/21 15:32
字数 1523
阅读 7
收藏 0

一、前言

命令也是类,将命令作为一个类来保存,当要使用的时候可以直接拿来使用,比如脚本语言写出的脚本,只需要一个命令就能执行得到我们想要的需要操作很长时间才能得到的结果。这是一个非常有意思的模式,将操作的步骤保存下来,本例中我们使用java自带的GUI来画图,然后将画图的过程保存下来,可以把每一次我们的操作作为一个命令,将这个命令对应的对象保存到所有命令对象的集合中去,这样命令集合就记录下来了每一个命令,如果要显示画的内容的时候,直接将这些命令组合读取出来再进行一次重画即可。通过这种模式保存下来已经执行的步骤,通过重画再复述出来,是一种非常重要的开发理念,在需要保存历史记录并恢复的场合是非常有用的。

二、代码

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) {
    }
}

由此我们可以看到保存了的命令就这样一个个的再次执行了一遍,是不是很有意思呢?!

  让我们分析一下程序执行的过程:

  1、开始执行初始化界面,然后显示:

public static void main(String[] args) {
 
        new Main("命令模式");
         
     }

   2、然后等待用户的操作,当监听到用户在界面上拖动鼠标的时候,执行:

    @Override
     public void mouseDragged(MouseEvent e) {
        Command cmd=new DrawCommand(canvas,e.getPoint());
         history.append(cmd);
         cmd.execute();
     }

  3、创建一个命令对象,然后记录进命令堆栈之中,之后我们跟踪 cmd.execute();

package zyr.dp.command;
 
 public interface Command {
    public abstract void execute();
 }

  4、这里就看到我们的面向抽象编程的好处了,根本不需要知道是谁执行了我们的命令,在命令的时候自然知道了,那就是new DrawCommand(canvas,e.getPoint());我们继续跟踪:

public class DrawCommand implements Command {
          。。。
     public void execute() {
         drawable.draw(position.x, position.y);
     }
 }

  5、继续跟踪:

1 package zyr.dp.command;
2 
3 public interface Drawable {
4 
5     public abstract void draw(int x,int y);
6     
7 }

  6、同理,谁实现了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();所走的流程,这就是命令模式,现在很清晰了。

三、总结

对于命令模式,在本例中使用了Composite模式,迭代器模式等作为辅助,另外在生成对象的时候还可能使用原型模式,在保存命令的时候还可能使用备忘录模式。本例是一个很好的例子,在本质上说明了命令模式就是将命令抽象成一个类,通过保存接收者的引用,在后期还可以让接收者去执行,同样的使用了组合模式将这些对象一个个的保存下来,然后一步步的调用单个命令的执行方法,该执行方法通过命令的接收者去再次执行命令,这种方式特别的方便,因为我们保存的是用户的操作,能够一直记录下来,甚至可以保存到文件后恢复,由此可以看到命令模式的强大。

 

浅谈设计模式<最通俗易懂的讲解>

© 著作权归作者所有

上一篇: 素小暖自传
青衣霓裳
粉丝 105
博文 95
码字总数 203796
作品 0
大连
私信 提问
《PHP设计模式大全》系列分享专栏

《PHP设计模式大全》已整理成PDF文档,点击可直接下载至本地查阅 https://www.webfalse.com/read/201739.html 文章 php设计模式介绍之编程惯用法第1/3页 php设计模式介绍之值对象模式第1/5页...

kaixin_code
2018/11/06
192
0
23种设计模式(10):命令模式

定义:将一个请求封装成一个对象,从而让你使用不同的请求把客户端参数化,对请求排队或者记录请求日志,可以提供命令的撤销和恢复功能。 类型:行为类模式 类图: 命令模式的结构 顾名思义,...

LCZ777
2014/07/07
75
0
Java单例设计模式的理解与常规实现方式

1:Java中单例模式是一种常见的设计模式,单例模式有以下特点:   单例模式确保某个类只有一个实例,而且自行实例化并向整个系统提供这个实例。 2:java中单例模式的写法也有很多种,我在这...

动力节点
01/02
0
0
Ubuntu中vi卸载与安装/使用模式

Ubuntu中安装的vi是vim-common版本,与centos系统中vi使用方式不同,编辑使用不惯, 遂卸载重装,卸载命令:sudo apt-get remove vim-common 卸载完毕后重新安装;输入命令:sudo apt-get in...

唐十三郎
2018/11/27
252
0
浅谈Java设计模式之——抽象工厂模式

版权声明:本文为博主原创文章,遵循 CC 4.0 BY 版权协议,转载请附上原文出处链接和本声明。 https://blog.csdn.net/azhon/article/details/90614321 上一篇文章我们介绍了一下,这一节就接着...

Code-Porter
05/27
0
0

没有更多内容

加载失败,请刷新页面

加载更多

前端的一些雕虫小技,从100%和滚动条说起

1、100%和滚动条 当我们在css中把html和body同时设为100%时,会出现滚动条 html, body { width: 100%; height: 100%; } 原因是html和b...

wphmoon
37分钟前
6
0
电力区块链应用案例【2019】

随着区块链技术的日益普及,出现了大量创业企业尝试使用区块链技术来解决能源与电力行业中存在的问题。在本文中,我们将介绍其中的三个能源区块链项目。 能源行业以价格不透明著称:消费者很...

汇智网教程
59分钟前
7
0
聊聊rocketmq的adjustThreadPoolNumsThreshold

序 本文主要研究一下rocketmq的adjustThreadPoolNumsThreshold DefaultMQPushConsumer rocketmq-client-4.5.2-sources.jar!/org/apache/rocketmq/client/consumer/DefaultMQPushConsumer.ja......

go4it
今天
10
0
关于早起

早起是非常好的事情,但是像如果前一天睡得晚,或者第二天早上是非常冷的时候,那就不是很美好了。 但是本身早起是一件非常棒的事情,我记得我每次早起 如果不觉得困的话,世界是那么安静,脑...

T型人才追梦者
今天
7
0
Java输入输出

JDK中的InputStream/OutputStream构成了IO输入输出继承层次的基础。它们都是面向字节序列的,每次可以从序列中读入或者写出一个字节或者指定大小的字节数组。但是面向字节流的输入输出不便于...

ytuan996
今天
6
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部