1

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

风格一:

    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");
}

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

4

3 回答 3

2

我通常不喜欢第二种样式,因为它在两个按钮之间以及它们的容器之间创建了耦合。

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

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

事实上,通过遵循选项 #2,您将另一个责任赋予容器 - 它执行事件路由。该工具包已经为您进行了事件路由 - 只要单击,它将调用正确的事件处理程序。使用此选项,您正在重新发明轮子。

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

请注意,我理解想要集中事件处理的情绪;然而,那是微观管理。GUI 编程既困难又乏味。事件处理是 GUI 编程中比较烦人的事情之一。这是您不必为自己安排路线和管理自己而感到高兴的第一件事。在很少有令人信服的情况下,您可以比工具包更好地管理事情。

于 2009-07-07T02:45:48.000 回答
0

Answer from Uri gave me some idea about matching the action with listener. I've just come out with a modified version of the first approach.

    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();
    }

It seems like I am going to create a bunch of classes though, instead of creating Listener classes, I create Command classes.

Normally Controller class can control view class & modal class. However in this case, I can't access view component directly, unless I make them inner classes. I think same goes to individual listener class approach. Any solution on this?

于 2009-07-07T05:01:41.590 回答
0

在我看来,这是“取决于”可能是您将得到的最佳答案的事情之一。如果你正在做一些快速而肮脏的事情,那么第一个会更快更容易。如果您正在开发一个真正的应用程序,您将重视关注点的分离,第二次购买您(尽管我可能希望看到 ActionListener 的东西在它自己的整个类中)。

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

第一个的缺点是在你的代码中分散监听器,但它通常也更容易找到处理特定元素的监听器,它可以更加灵活,如果你有多个元素,它可能比运行一个巨大的 if-else if 块要丑得多。

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

也就是说,这真的取决于情况。如果我正在开发一个只有几个操作的小型应用程序,我将采取哪条路线?首先。它最初更快、更清晰,并在代码中将元素和操作连接在一起,至少在开始时,维护工作更少。如果我正在开发一个更大的应用程序呢?我会创建一个单独的类,它是一个 ActionListener 并让它成为一个专用控制器。从长远来看,它会更干净,并且在任何实际大小的应用程序上,您都会很高兴从长远来看您做到了。

于 2009-07-07T03:23:48.780 回答