首页 > 代码库 > 命令模式之2 Invoker Vs. Client

命令模式之2 Invoker Vs. Client

当程序中直接编写下达命令的语句如new Cmd1().execute()时,通常会将调用者与客户类合二为一

在GUI程序中,下达命令的语句通常包含在底层框架中,或者说底层框架包含了调用者,这时程序员编写的程序都是客户类。

GUI程序中,由系统作为命令调用者在某种界面事件发生时自动调用命令。


下面的演示程序中使用了按钮、下拉菜单(JMenuBar-JMenu- JMenuItem)和弹出菜单(JPopupMenu),而JButton 、JMenuItem和JPopupMenu均可以通过其构造器注入一个Action命令。(依赖注入)

下面将编写两个AbstractAction的子类,它们将被注入到相应的控件中。

值得注意的是,具体命令类自己实现所有功能,不需要额外的接收者。在此情况下,既可以说应用了命令模式(编写了两个子命令),也可以说简单的应用了回调(编写了两个包含回调函数的类)。

yqj2065个人认为,命令模式的概念还是小一点好:具体命令指定执行者(可以是抽象类型)和被调用的方法,将C/S结构的C与S解耦。

GoF的:“将(客户端的)请求封装为一个对象,从而使你可用不同的请求对客户进行参数化”。过于泛泛而谈。“将(客户端的)请求封装为一个对象",参见方法类型化,是Java接口的一般意图;客户下达的cmd.exe(),在多态的场合都是”用不同的请求对客户进行参数化“。当不需要接收者的时候,我们甚至可以把AbstractAction的actionPerformed(ActionEvent evt)视为一个策略,也是可以的,难道我们说此例程使用了策略模式??

不管怎么说,GUI中的这种应用,是命令模式的典型案例。

如果你的程序中多处使用某种按钮如Exit,可以使用命令模式编写一个命令,而不是随地使用匿名类

例程 3-22命令
package method.command.gui;
import javax.swing.*;
import java.awt.event.*;
import java.awt.*;
class SubmitAction extends AbstractAction {
   private Component target;
   public SubmitAction(String name, Icon icon, Component t){
       putValue(Action.NAME, name);
       putValue(Action.SMALL_ICON, icon);
       putValue(Action.SHORT_DESCRIPTION, name + " the program");
       target = t;
   }    
   @Override public void actionPerformed(ActionEvent evt) {
       JOptionPane.showMessageDialog(target, "submit action ");
   }
}
class ExitAction extends AbstractAction {
   private Component target;
   public ExitAction(String name, Icon icon, Component t){
       putValue(Action.NAME, name);
       putValue(Action.SMALL_ICON, icon);
       putValue(Action.SHORT_DESCRIPTION, name + " the program");
       target = t;
   }    
   @Override public void actionPerformed(ActionEvent evt) {
       int answer = JOptionPane.showConfirmDialog(target, "Are you sure you want to exit? ", "Confirmation",
                           JOptionPane.YES_NO_OPTION);
       if ( answer == JOptionPane.YES_OPTION)  System.exit(0); 
   }
}
public class Test extends JFrame{
    Test() {
        Action ea = new ExitAction("Exit", null, this);
        Action sa = new SubmitAction("Submit", null, this);
        //下拉菜单(JMenuBar-JMenu- JMenuItem)
        JMenuBar bar = new JMenuBar();
        JMenu mn_demo= new JMenu("Demo");
        mn_demo.add(new JMenuItem(sa));
        mn_demo.add(new JMenuItem(ea));
        bar.add(mn_demo);
        this.setJMenuBar(bar);
        //JPopupMenu
        final JPopupMenu pop = new JPopupMenu("PopMenu");
        pop.add(sa);
        pop.add(ea);
        //
        addMouseListener(new MouseAdapter() {
            public void mousePressed(MouseEvent e) {
                showPopup(e);
            } 
            public void mouseReleased(MouseEvent e) {
                showPopup(e);
            }
            private void showPopup(MouseEvent e) {
                if (e.isPopupTrigger()) {
                    pop.show(e.getComponent(),e.getX(), e.getY());
                }
            }
        });
        JPanel jp = new JPanel();
        JButton subbtn = new JButton(sa);
        JButton exitbtn = new JButton(ea);
        jp.add(subbtn);
        jp.add(exitbtn);        
        Container con = getContentPane();
        con.add(jp, "South");

        setTitle("Command pattern example");
        setSize(300,200);
        setVisible(true);
    }
}


命令模式之2 Invoker Vs. Client