命令(Command)模式--------命令也是类

》》表示命令的类的实例,即可以用"物"来表示。要想管理工作的历史记录,

        只需管理这些实例的集合即可,而且还可以随时再次执行过去的命令,

        或是将过去的命令整合为一个新的命令并执行。

》》Command 有时也称为事件(event) ,它与“事件驱动程序”中的

        “事件“是一样的意思。当发生点击鼠标、按下键盘按键等事件时,我们

      可以先将这些事件作成实例,然后按照发生顺序放入队列中。接着,再

      依次去处理它们。在GUI 编程中,经常需要与”事件“打交道。

-------------------下面的示例程序是一个画图软件,它的功能很简单,即用户

          拖动鼠标时程序会绘制出红色圆点,点击 clear 按钮后会清除所有的

        圆点

》》运行的结果:

         

》》示例程序的类图:

          

》》Command 接口:

        package command.command;
/*
 * 该接口是表示“命令”的接口,该接口的作用是:“执行”什么东西
 */
public interface Command {
public abstract void execute();


}

》》MacroCommand  类:

        package command.command;
import java.util.Iterator;
import java.util.Stack;
/*
 * 该类表示“由多条命令整合成的命令”
 */
public class MacroCommand implements Command {
//命令的集合
private Stack commands = new Stack();
//执行
public void execute(){
//获取该栈的迭代器
Iterator it=commands.iterator();
while(it.hasNext()){
((Command)it.next()).execute();
}

}

//添加命令
public void append(Command cmd){
/*
* if 语句的作用是防止不小心将自己(this)添加进去。
* 如果这么做了,execute 方法将会陷入循环,永远不停地执行。
*/
if(cmd != this){
commands.push(cmd);
}
}

//删除最后一条命令
public void undo(){
if(!commands.empty()){
commands.pop();
}
}

//删除所有命令
public void clear(){
commands.clear();
}
}

》》DrawCommand 类:

          package command.drawer;


import java.awt.Point;


import command.command.Command;
/*
 * 该类表示“绘制一个点的命令”
 * 
 * Point类表示由 X轴 和 Y轴构成的平面上的坐标。
 */
public class DrawCommand implements Command {
//绘制对象
protected Drawable drawable;
//绘制位置
private Point position;
//构造函数
public DrawCommand(Drawable drawable , Point position){
this.drawable = drawable;
this.position = position;
}
//执行
public void execute(){
drawable.draw(position.x, position.y);
}


}

》》Drawable 接口:

         package command.drawer;
/*
 * 该接口表示“绘制对象”的接口,draw 方法是用于绘制的方法
 */
public interface Drawable {
public abstract void draw(int x ,int y);


}

》》DrawCanvas 类:

         package command.drawer;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Graphics;
import command.command.MacroCommand;
/*
 * 该类继承  Canvas ,Canvas 相当于一个 画布
 */


public class DrawCanvas extends Canvas implements Drawable{
//当前画笔的颜色
private Color color = Color.red;
//要绘制的圆点的半径
private int radius = 6;
//命令的历史记录
private MacroCommand history;
//构造函数
public DrawCanvas(int width , int height , MacroCommand history){
//设置画布的宽和高
setSize(width , height);
//设置画布的背景色
setBackground(Color.white);
this.history = history;

}

//重新全部绘制
public void paint(Graphics g){
history.execute();

}

//绘制
public void draw(int x ,int y){
//在该画布中获取画笔
Graphics g = getGraphics();
//设置该画笔的颜色
g.setColor(color);
//画圆点
g.fillOval(x-radius, y-radius, radius*2, radius*2);
}


}

》》Main 类:

      补充:在该类的构造函数中设置了用于接收鼠标按下等事件的监听器,

                 并安排了各个控件(组件)在界面中的布局。

                 在javax.swing.JFrame 中,必须将控件放置在通过getContentPane

                方法获取的容器之内。

         package command.drawer;
import javax.swing.BoxLayout;
import javax.swing.JFrame;
import javax.swing.JButton;
import javax.swing.Box;


import java.awt.Point;
import java.awt.event.ActionListener;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.awt.event.MouseMotionListener;
import java.awt.event.ActionEvent;
import java.awt.event.MouseEvent;


import command.command.Command;
import command.command.MacroCommand;


public class Main extends JFrame implements ActionListener,WindowListener,
    MouseMotionListener{
//绘制的历史记录
private MacroCommand history = new MacroCommand();
//绘制区域
private DrawCanvas canvas = new DrawCanvas(400,400,history);
//删除按钮
private JButton clearButton = new JButton("clear");

//构造函数
public Main(String title){
/*
* 调用父类 JFrame 里面构造函数  public JFrame(String title)
                                      throws HeadlessException
*/
super(title);
/*
* 对下面添加监听器时传入的参数的理解:该参数应该是实现了监听器(接口)里面的
* 方法的实例的引用
*/
//给当前窗口对象添加  窗口监听器
this.addWindowListener(this);
//给按钮添加 事件监听器
clearButton.addActionListener(this);
        //给画布添加鼠标移动监听器
canvas.addMouseMotionListener(this);

//在JFrame里面添加组件
Box buttonBox  = new Box(BoxLayout.X_AXIS);
buttonBox.add(clearButton);
Box mainBox = new Box(BoxLayout.Y_AXIS);
mainBox.add(buttonBox);
mainBox.add(canvas);
getContentPane().add(mainBox);
//调整此窗口的大小,以适合其子组件的首选大小和布局。
pack();
//代替 show() 显示出来
setVisible(true);
}

//java.awt.event.ActionListener 接口里面的方法,发生操作时
//会调用下面的方法
public void actionPerformed(ActionEvent e){
//getSource():获取最初发生 Event 的对象
if(e.getSource() == clearButton ){
//清除所有的命令
history.clear();
//重绘此组件。
canvas.repaint();
}

}
/*
*java.awt.event.WindowListener 接口里面的方法
*/
//将 Window 设置为活动 Window 时调用。只有框架或对话框可以成为活动 Window。
public void windowActivated(WindowEvent e){

}
//窗口首次变为可见时调用。
public void windowOpened(WindowEvent e){

}
//用户试图从窗口的系统菜单中关闭窗口时调用。 
public void windowClosing(WindowEvent e){
System.exit(0);
}
//因对窗口调用 dispose 而将其关闭时调用。
public void windowClosed(WindowEvent e){

}
//窗口从正常状态变为最小化状态时调用。
public void windowIconified(WindowEvent e){

}
//窗口从最小化状态变为正常状态时调用。
public void windowDeiconified(WindowEvent e){

}
//当 Window 不再是活动 Window 时调用。
public void windowDeactivated(WindowEvent e){

}


/*
* java.awt.event.MouseMotionListener 
* 接口中的方法
*/
//鼠标按键在组件上按下并拖动时调用。
public void mouseDragged(MouseEvent e){
//e.getPoint() 返回鼠标当前位置(已经按下)相对于源组件的 x, y 坐标。 
Command cmd = new DrawCommand(canvas , e.getPoint());
   history.append(cmd);
   cmd.execute();
}
//鼠标光标移动到组件上但无按键按下时调用。 
public void mouseMoved(MouseEvent e){

}
public static void main(String[] args){
new Main("Command Pattern Sample");
}


}

--------------------------------------

     《控件布局》

      

-----------------------------------------------------------------------

        《Command 模式中的登场角色》

         ***   Command ( 命令)

                  Command 角色负责定义命令的接口。在示例程序中,由 Command 接口扮演此角色。

         *** ConcreteCommand (具体的命令)

                ConcreteCommand 角色负责实现在 Command 角色中定义的接口。在示例程序中,由

                MacroCommand 类 和 DrawCommand 类扮演此角色。

         *** Receiver (接收者)

               Receiver 角色是 Command 角色执行命令时的对象,也可以称其为命令接收者。在示例

               程序中 由 DrawCanvas 类接收  DrawCommand 的命令。

         *** Client (请求者)

                Client 角色负责生成 ConcreteCommand 角色并分配 Receiver 角色。在示例程序中,由

                Main 类扮演此角色。在响应鼠标拖拽事件时,它生成了  DrawCommand  类的实例,并

               将扮演 Receiver 角色的 DrawCanvas 类的实例传递给了DrawCommand 类的构造函数。

         ***  Invoker (发动者)

                Invoker 角色是开始执行命令的角色,它会调用在Command 角色中定义的接口。在示例

               程序中,由 Main 类和 DrawCanvas 类扮演此角色。这两个类都调用了 Command 接口中

                的 execute 方法。Main 类同时扮演了  Client 角色 和 Invoker 角色。

----------------------------------------------------------------------------------------

             《扩展思路的要点》

              1.命令中应该包含哪些信息

                      ****命令的目的不同,应该包含的信息也不同。

                      **** 在上面示例中,DrawCommand 类中的 drawable 字段表示的是绘制对象(具体的

                          命令接收者)。

                      *** 在 ConcreteCommand 角色中只要知道自己的 Receiver 角色,不论谁来管理或持有

                           ConcreteCommand 角色,都可以执行 execute 方法的。

              2.保存历史记录

                       ***  在Main 类中,MacroCommand 类的实例(history)代表了绘制的历史记录。在该

                          字段中保存了之前所有的绘制信息。也就是说,如果我们将它保存为文件,就可以永久

                          保存历史记录。

              3.适配器

                       ***在 Main 类中,我们实现了 3 个接口:ActionListener 、WindowListener 、

                          MouseMotionListener  。这三个接口下面的方法,都需要进行实现(即使是空的方法)

                          有的方法调用了,有的方法没有调用。

                       *** 为了简化程序,java.awt.event 提供了一些被称为适配器(Adapter)的类。

                                

                       ****  在适配器中已经实现了接口中所定义的所有方法。不过,所有的实现都是空

                    (即什么都不做)的。因此,我们只要编写一个 适配器的子类,然后实现所需要的

                    方法即可,而不必在意其他不需要的方法。

                       **** 特别是把 java 匿名内部类适配器结合起来使用时,可以更轻松地编写程序。

                       **** 在编译匿名内部类时,生成的类文件的名字会像下面这样,其命名规则是:

                              “主类名 $ 编号.class”

                              eg: Main$1.class

-------------------------------------------------------------------------

                       《相关的设计模式》

                      **** Composite 模式

                      **** Memento 模式

                      **** Prototype 模式

                

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小达人Fighting

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值