让方法运行的最常见方式调用之。但是在很多情况下,我们不能控制和提供方法执行的时机或者上下文。 在这些情况下,可以把方法封装在对象中。通过在对象中存储调用方法所需的信息,就可以让客户端或者服务决定何时调用这个方法。
Commmand模式的意图是把请求封装在对象中。
1.经典范例:菜单命令
支持菜单的工具集通常都会用到Command模式。每个菜单项都需要配置一个对象,当用户单击它时,可以执行所绑定的对象。这种设计思想使GUI程序逻辑和应用逻辑可以分离开。Swing库就采用这种方法,允许把ActionListener与每个JmenuItem关联起来。
我们该如何安排才能让一个类在用户单击菜单时调用对应的方法呢?解决的方法就是应用多态性,具体做法如下:首先将操作的名称固定,然后针对不同的类给出不同的实现。对于JMenuItem类而言,该操作就是actionPerformed()。当用户选择某个菜单项的时候,JMenuItem对象就调用其监听器对象的actionPerformed()方法。
突破题:java的菜单机制使得Command模式可以很容易地应用于菜单的制作,但是我们并不一定要应用Command模式来组织代码。事实上,在应用程序的开发过程中,通常会用单个对象来监听GUI中的所有事件,请问这种做法遵循了哪一种设计模式?
答:Java Swing应用程序通常应用中介者模式,注册单个对象来接收所有的GUI事件。该对象可以仲裁图形组件的交互,并将用户的输入转换为控制业务域对象的命令。
当我们在开发Swing应用程序的时候,我们可能会注册单个对象来监听应用程序中的所有GUI事件,特别是在GUI组件交互的时候。不过,对于菜单而言,这并不是最佳的设计模式。如果我们用单个对象作为所有GUI事件的监听器,那么当有事件发生的时候,该对象必须查询出产生事件的GUI对象。而如果在应用程序中有许多菜单项,且它们都对应不同的操作,那么我们最好是应用command模式。
当用户选择某菜单项的时候,调用的方法是actionPerformed()。当你创建该菜单项时,可以使用对应于特定命令行为的actionPerformed()方法,给它绑定一个监听器对象(ActionListener)。我们可以定义一个新类来实现这个小功能;不过,更好的做法是,直接使用一个匿名类来实现。
com.oozinoz.visualization包中的Visualization2类提供了一个“文件”菜单条,包括“Save as ...”,“Restore from ...“两个菜单项。它们分别注册了一个监听器,用于监听用户的单击事件。这两个监听器分别实现了actionPerformed()方法,并分别调用了Visualization2类的save()方法和load()方法。
package com.oozinoz.visualization;
import java.awt.event.*:
import javax.swing.*;
import com.oozinoz.ui.*;
public class Visualization2 extends Visualization
{
public static void main(String[] args)
{
Visualization2 panel = new Visualization2(UI.NORMAL);
JFrame frame = SwingFacade.launch(panel,"Operational Model");
frame.setJMenuBar(panel.menus());
frame.setVisible(true);
}
public Visualization2(UI ui){
super(ui);
}
public JMenuBar menus(){
JManuBar menuBar = new JMenuBar();
JMenu menu = new JMenu("File");
menuBar.add(menu);
JMenuItem menuItem = new JMenuItem("Save As...");
menuItem.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
save();
}
});
JMenuItem menuItem = new JMenuItem("Restore From...");
menutItem.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
restore();
}
});
menu.add(menuItem);
return menuBar;
}
public void save(){
try {
mediator.save(this);
} catch (Exception ex) {
System.out.println("Failed save: " + ex.getMessage());
}
}
public void restore(){
try {
mediator.restore(this);
} catch (Exception ex) {
System.out.println("Failed restore: " + ex.getMessage());
}
}
}
当为一个菜单添加各种命令之后,你还必须将命令应用于其他开发者提供的上下文:Java菜单框架。在Command模式的某些应用场合,你还必须承担上下文开发者的角色,创建命令执行的上下文。例如,我们可能会提供计时服务来记录方法的执行时间。