Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Java: Общие вопросы > Как лучше реализовывать интерфейс обраб. событий?


Автор: 604 15.4.2005, 14:21
Как лучше реализовывать интерфейс обраб. событий? В классе который содержит компоненты на которые вешаются события или в отдельном?
я вижу 2 варианта:

Тут мы не содаем доп. классов но если много слушателей тогда приходится строить кучу условий.
Код

public class Test implements ActionListener
{
    JButton bt1 = new JButton("Bt1");
    JButton bt2 = new JButton("Bt1");
    public Test() {
        bt1.addActionListener(this);
        bt2.addActionListener(this);
    }
    
    public void actionPerformed(ActionEvent e) {
        if (e.getSource().equals(bt1)) { // Some action 
        }
        else if (e.getSource().equals(bt2)) { //Enother action
        }
    }
}

Тут мы избавились от условий но получаем много анонимных классов (Возможно загрузка класса более ресурсоёмкая задача?)
Код

public class Test2
 {
    JButton bt1 = new JButton("Bt1");
    JButton bt2 = new JButton("Bt1");
    public Test2(){
        bt1.addActionListener(new ActionListener(){
            public void actionPerformed(ActionEvent e){
                new userDetailsWnd(12, "", "").setVisible(true);
            }
        });

        bt2.addActionListener(new ActionListener(){
            public void actionPerformed(ActionEvent e){
                new userDetailsWnd(12, "", "").setVisible(true);
            }
        });
    }
}

Собственно теперь вопрос! Как делать правильно, и какой из вариантов лучше? Или нужно совсем иначе?

Автор: batigoal 15.4.2005, 15:35
Попробовал провести тест.
Код

import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;

public class Form extends JPanel implements ActionListener
{
    ArrayList buttons = new ArrayList();
    public final static int MAX = 100;

    public Form()
    {
        JButton btn;
        for(int i = 0; i<MAX; i++)
        {
            btn = new JButton("Button "+Integer.toString(i));
            this.add(btn);
            btn.addActionListener(this);
            buttons.add(btn);
        }
    }

    public void actionPerformed(ActionEvent e)
    {
        Object source = e.getSource();
        for(int i = 0; i<MAX; i++)
        {
            if(source.equals(buttons.get(i)))
            {
                return;
            }
        }
    }

    public static void main(String[] args)
    {
        final JFrame frame = new JFrame("Form");
        final Form f = new Form();
        frame.setContentPane(f);
        frame.setSize(200, 200);

        long time = System.currentTimeMillis();
        for(int i=0; i<MAX; i++)
        {
            ((JButton)f.buttons.get(i)).doClick();
            ((JButton)f.buttons.get(i)).doClick();
            ((JButton)f.buttons.get(i)).doClick();
        }
        time = System.currentTimeMillis() - time;

        System.out.println(time);

        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        frame.show();

    }
}


Код

import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;

public class Form extends JPanel
{
    ArrayList buttons = new ArrayList();
    public final static int MAX = 100;

    public Form()
    {
        JButton btn;
        for(int i = 0; i<MAX; i++)
        {
            btn = new JButton("Button "+Integer.toString(i));
            this.add(btn);
            btn.addActionListener(new ActionListener(){
                public void actionPerformed(ActionEvent e)
            {
                return;
            }});
            buttons.add(btn);
        }
    }

    public static void main(String[] args)
    {
        final JFrame frame = new JFrame("Form");
        final Form f = new Form();
        frame.setContentPane(f);
        frame.setSize(200, 200);

        long time = System.currentTimeMillis();
        for(int i=0; i<MAX; i++)
        {
            ((JButton)f.buttons.get(i)).doClick();
            ((JButton)f.buttons.get(i)).doClick();
            ((JButton)f.buttons.get(i)).doClick();
        }
        time = System.currentTimeMillis() - time;

        System.out.println(time);

        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        frame.show();

    }
}


Результаты почти идентичны:
Однократное нажатие каждой кнопки: 6940 против 6860.
Потом попробовал эмулировать трехкратное нажатие (как в коде): 20900 против 20590.
Можно было бы оптимизировать поиск в массиве, но не стал - ведь в общем случае у тебя не массив, а именно перебор.

Автор: AntonSaburov 15.4.2005, 17:36
IMHO надо делать так, чтобы было удобно читать, править и расширять. Общие принципы обычно имеют критерии как и для обычного ООП.

Автор: Domestic Cat 15.4.2005, 18:20
Есть еще Command паттерн, правда придется сабклассить каждый баттон. Можно листенером сделать не сам класс с гуем, а отдельный делегат.

Автор: NotGonnaGetUs 17.4.2005, 13:45
Цитата(Domestic @ 15.4.2005, 18:20)
Есть еще Command паттерн, правда придется сабклассить каждый баттон. Можно листенером сделать не сам класс с гуем, а отдельный делегат.

Если речь идёт за тот "Комманд паттерн", который описан в http://forum.vingrad.ru/index.php?showtopic=41784&st=30,
то лучше забыть о нём.
Хотя бы потому, что листенер на бутон всё равно вешается, и этот листенер есть сам бутон.

"Нормальный" комманд паттерн предполагает, что у нас есть набор однотипных заданий (комманд, классов с общим интерфейсом) и исполнитель этих задний.

На практике всё можно изуродывать под конретную задачу.
Возмём тот же ГУИ с кнопочками.

При инициализации панели создаём класс контроллер.
Каждому активному объекту вешаем листенер, который делегирует событие контроллеру.
Код


класс Контроллер {
      private Vector commands = new Vector();
      private SomeDataToProcessEvents s;
      Контроллер(SomeDataToProcessEvents s){
               this.s=s;
      }
      void add(Command c)  {
            commands.add(c);
      }
      войд execute(){
           new Thread(){ 
                  public void run() {
                     while(commands.size()>0) {
                             ((Command)commands.remove(0)).execute(s);
                     }
                 }
           }.start();
      }
}


класс МояПанель дитё ЖПанель {
        private Контроллер контроллер;
        private SomeDataToProcessEvents s = new SomeDataToProcessEvents();

        void init(){       
                //setup controlls
                final Button b = new Button("xxx"));
                add(b);
                ...
                //setup контроллер
                контроллер = new Контроллер(s);
                ...
                //запускаем логику
                b.addActionListener(new ActionListener(){
                        public void actionPerformed(Event e){
                                  b.setEnable(true);
                                  контроллер.add(new SendMailTo());
                                  контроллер.add(new Command(){
                                           void execute(...){ 
                                                    SwingUtilites.invokeLater(new Runnable(){
                                                        void run(){
                                                               b.setEnable(true);
                                                        }
                                                    });
                                           }
                                  })
                                  контроллер.execute(); 
                        }
                });
               ...
       }
}

класс SendMailTo дитё Commad {
         войд execute(SomeDataToProcessEvents s){
                ...send mail or smth else...
         }
}



Следующий шаг это вручение каждому активного компоненту уникального ID и составление таблицы
"ID - Комманда1, Комманда2...", что бы изменение логики можно было производить правкой файла пропертисов или xml, не меняя код инициализации.

Можно строить один большой контроллер, можно строить иерархию контроллеров по типу того, как сделано в маверике.
Короче говоря простор для творчества большой smile


з.ы. сорри, пример на ходу придумывал smile

Автор: batigoal 17.4.2005, 14:05
Цитата(NotGonnaGetUs @ 17.4.2005, 13:45)
что бы изменение логики можно было производить правкой файла пропертисов или xml, не меняя код инициализации

А надо ли оно нам? Интерфейс приложениия меняется не так уж часто... Имхо, не стоит усложнять код.

Автор: NotGonnaGetUs 17.4.2005, 14:46
Вам наверное не надо smile

Автор: Domestic Cat 17.4.2005, 18:05
Цитата(NotGonnaGetUs @ 17.4.2005, 04:45)
з.ы. сорри, пример на ходу придумывал smile


Ты извини, это не код... При пятом нажатии на кнопку будет выполнено 5 раз
SendMailTo.execute и 5 раз Command.execute. У анонимных классов доступа к локальным переменным в коде нет . И т п.

Автор: NotGonnaGetUs 19.4.2005, 10:33
Цитата(Domestic @ 17.4.2005, 18:05)
Цитата(NotGonnaGetUs @ 17.4.2005, )
з.ы. сорри, пример на ходу придумывал smile


Ты извини, это не код...

Есть такое, my bad. Поправил.

Как вариант можно описать требования к ГУИ и реализовать его выше описанными способами.
Будет наглядно и полезно smile

Автор: Гость_604 22.4.2005, 09:51
Всем спасибо! Насколько я понял, ничего плохого в моем коде нет, так что оставлю все как есть.

Автор: Zandr 22.4.2005, 11:58
Цитата
У анонимных классов доступа к локальным переменным в коде нет

В каком смысле? Пример хочу smile

Автор: batigoal 22.4.2005, 12:22
Цитата(Zandr @ 22.4.2005, 11:58)
У анонимных классов доступа к локальным переменным в коде нет

Вроде есть...
Добавлено @ 12:23
Если она final

Автор: Zandr 22.4.2005, 12:29
Собсна об этом я и писал smile
http://forum.vingrad.ru/index.php?showtopic=48585&view=findpost&p=387904

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)