在OOP中添加/注册按钮侦听器的样式(Java、Actionscript等)

在OOP中添加/注册按钮侦听器的样式(Java、Actionscript等),java,oop,button,listener,observer-pattern,Java,Oop,Button,Listener,Observer Pattern,在UI中添加按钮侦听器时,我遇到了两种不同的样式。我以SWT为例。但尽管如此,我还是在J2ME中看到了类似的代码,Flash Actionscript也是如此 风格1: b1.addSelectionListener(new SelectionListener() { public void widgetSelected(SelectionEvent e) { System.out.println("b1: ");

在UI中添加按钮侦听器时,我遇到了两种不同的样式。我以SWT为例。但尽管如此,我还是在J2ME中看到了类似的代码,Flash Actionscript也是如此

风格1:

    b1.addSelectionListener(new SelectionListener()
    {
        public void widgetSelected(SelectionEvent e)
        {
            System.out.println("b1: ");
        }

        public void widgetDefaultSelected(SelectionEvent e)
        {
            System.out.println("Default selection");
        }
    });

    b2.addSelectionListener(new SelectionListener()
    {
        public void widgetSelected(SelectionEvent e)
        {
            System.out.println("b2: ");
        }

        public void widgetDefaultSelected(SelectionEvent e)
        {
            System.out.println("Default selection");
        }
    });
风格2:

    b1.addSelectionListener(this);
    b2.addSelectionListener(this);

public void widgetSelected(SelectionEvent e)
{
    if (e.getSource() == b1)
    {
        System.out.println(b1);
    } 
    else if (e.getSource() == b2)
    {
        System.out.println(b2);
    }

}

public void widgetDefaultSelected(SelectionEvent e)
{
    System.out.println("Default selection");
}

就个人而言,我更喜欢第二种风格,因为它为我提供了一种集中处理鼠标事件的方法。你喜欢哪种款式?为什么呢?

我通常不喜欢第二种样式,因为它会在两个按钮之间以及与它们的容器之间产生耦合

如果B1和B2的功能是独立的,B1不应该了解B2,反之亦然。通过共享事件处理程序,您不仅进行了浪费性的检查,而且还破坏了这种独立性。他们现在分享他们的处理方式

此外,通过选择2,您现在已经耦合了三个类:B1、B2和具有处理机制的容器。另一方面,如果您遵循选项1,B1耦合到它的个人处理程序,B2耦合到它自己的个人处理程序,容器不需要知道任何关于这两个处理程序的信息

事实上,通过遵循选项2,您将另一项责任交给了容器—它执行事件路由。工具箱已经为您执行了事件路由-单击一下,它将调用正确的事件处理程序。使用此选项,您将重新发明轮子

如果每个按钮的处理都足够复杂,那么创建按钮的两个子类并让每个子类安装自己的侦听器可能是有意义的。然后,您的容器只是实例化按钮,而不必实际包含用于处理事件的代码(即使是匿名类)


注意,我理解希望集中事件处理的情绪;然而,这是微观管理。GUI编程已经够辛苦和乏味的了。事件处理是GUI编程中最烦人的事情之一。这是你应该高兴的第一件事之一,因为你不必自己安排路线和管理自己。很少有令人信服的情况下,你可以管理的东西比工具包更好

在我看来,这是“视情况而定”可能是最好的答案之一。如果你在做一些又快又脏的事情,那么第一步会更快更容易。如果您正在开发一个真正的应用程序,那么您将重视第二个应用程序带来的关注点分离(尽管我可能希望看到ActionListener在自己的整个类中的内容)

值得一提的是,我不久前学习Swing时看到的几乎所有介绍Swing的材料都采用了第二种方法

    private Map<Control, ICommand> commandMap = new HashMap<Control, ICommand>();
    private HelloCommand helloCommand = new HelloCommand();
    private WorldCommand worldCommand = new WorldCommand();

    protected Control createContents(Composite parent)
    { ...
            b1.addListener(this);
            b2.addListener(this);
        commandMap.put(b1, helloCommand);
        commandMap.put(b2, worldCommand);   
    }

    public void widgetSelected(SelectionEvent e)
    {
        ICommand command = commandMap.get(e.getSource());
        command.execute();
    }
第一种方法的缺点是将监听器分散在代码周围,但它通常也会使查找处理特定元素的监听器变得更容易,而且它可以更灵活,如果您有多个元素,那么与运行一个巨大的if-else-if块相比,它的丑陋性要小得多

但是第二种方法更清晰地分离了代码——监听器是控制器逻辑,视图(GUI)不应该关心它们做什么。它还集中了您的控制器逻辑:如果您需要更改某些内容,它就在那里。如果您进行任何web应用程序编程,那么第二种方法看起来会更加熟悉


也就是说,这实际上取决于环境。如果我正在开发一个只有几个操作的小应用程序,我将采取哪种方法?第一个。它最初更快、更干净,并且在代码中将元素和动作连接在一起,至少在开始时,维护起来更省力。如果我正在开发一个更大的应用程序呢?我将创建一个单独的类,它是一个ActionListener,并且是一个专用的控制器。从长远来看,它更干净,在任何实际大小的应用程序上,从长远来看,您都会很高兴您做到了这一点。

Uri的回答让我了解了如何将操作与侦听器匹配。我刚刚提出了第一种方法的修改版本

    private Map<Control, ICommand> commandMap = new HashMap<Control, ICommand>();
    private HelloCommand helloCommand = new HelloCommand();
    private WorldCommand worldCommand = new WorldCommand();

    protected Control createContents(Composite parent)
    { ...
            b1.addListener(this);
            b2.addListener(this);
        commandMap.put(b1, helloCommand);
        commandMap.put(b2, worldCommand);   
    }

    public void widgetSelected(SelectionEvent e)
    {
        ICommand command = commandMap.get(e.getSource());
        command.execute();
    }
private-Map commandMap=new-HashMap();
私有HelloCommand HelloCommand=新HelloCommand();
private WorldCommand WorldCommand=new WorldCommand();
受保护的控件createContents(复合父级)
{ ...
b1.添加侦听器(本);
b2.addListener(本);
commandMap.put(b1,helloCommand);
commandMap.put(b2,worldCommand);
}
公共无效WidgeSelected(SelectionEvent e)
{
ICommand命令=commandMap.get(例如getSource());
command.execute();
}
看起来我要创建一组类,而不是创建侦听器类,而是创建命令类


通常控制器类可以控制视图类和模态类。然而,在这种情况下,我不能直接访问视图组件,除非我将它们设置为内部类。我认为个人监听类方法也是如此。有什么解决办法吗?

1。对于第一种方法,如果我有10个按钮,我需要实例化10个侦听器类?对于第二种方法,我需要再添加一个条件检查,但它不会消耗那么多内存,尽管它可能运行得有点慢。2.对于第二种方法,我可以通过调用RemovelListener(this)来删除侦听器。我不知道如何使用anonymous listener.Swing(以及一般的GUI)来实现这一点,因为它非常重,一些实例化处理程序的成本非常低,特别是因为代码是单独存储的。对象的占用空间最小。至于删除侦听器,当关闭时,调用getActionListeners()获取所有关联的侦听器,然后迭代所有侦听器,并在每个侦听器上调用RemovelListener。