让方法运行的最常见方式调用之。但是在很多情况下,我们不能控制和提供方法执行的时机或者上下文。 在这些情况下,可以把方法封装在对象中。通过在对象中存储调用方法所需的信息,就可以让客户端或者服务决定何时调用这个方法。
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模式的某些应用场合,你还必须承担上下文开发者的角色,创建命令执行的上下文。例如,我们可能会提供计时服务来记录方法的执行时间。
