Создать пользовательское событие в Java


193

Я хочу сделать что-то подобное в Java, но я не знаю, как это сделать:

Когда происходит событие «объект 1 сказать« привет »», тогда объект 2 отвечает на это событие, говоря «привет».

Может кто-нибудь дать мне подсказку или пример кода?



Ответы:


421

Вы, вероятно, хотите посмотреть на паттерн наблюдателя .

Вот пример кода, чтобы начать работу:

import java.util.*;

// An interface to be implemented by everyone interested in "Hello" events
interface HelloListener {
    void someoneSaidHello();
}

// Someone who says "Hello"
class Initiater {
    private List<HelloListener> listeners = new ArrayList<HelloListener>();

    public void addListener(HelloListener toAdd) {
        listeners.add(toAdd);
    }

    public void sayHello() {
        System.out.println("Hello!!");

        // Notify everybody that may be interested.
        for (HelloListener hl : listeners)
            hl.someoneSaidHello();
    }
}

// Someone interested in "Hello" events
class Responder implements HelloListener {
    @Override
    public void someoneSaidHello() {
        System.out.println("Hello there...");
    }
}

class Test {
    public static void main(String[] args) {
        Initiater initiater = new Initiater();
        Responder responder = new Responder();

        initiater.addListener(responder);

        initiater.sayHello();  // Prints "Hello!!!" and "Hello there..."
    }
}

Связанная статья: Java: создание пользовательского события


Есть ли законная причина, по которой stackoverflow.com/suggested-edits/237242 не прошел? Это показывает, как сделать это с 2 классами, как первоначально заданный вопрос.
GlassGhost

2
Что, если несколько потоков генерируют исходные события, будет ли это правильно синхронизировано?
Майк Дж

Зависит от сируации. Каждый слушатель будет уведомлен в соответствии с порядком их регистрации. (Кстати, я не понимаю, что вы подразумеваете под несколькими потоками здесь. Код слушателя будет задействован в том же потоке, который вызвал событие.)
aioobe

8
@GlassGhost: он был отклонен, потому что это было в основном полное переписывание. Правки чужого ответа хороши, если они исправляют опечатки, форматирование и неработающие ссылки и т. Д., Но они не должны радикально изменять содержимое. (Некоторые исключения применяются к сообщениям с пометкой «Вики сообщества».)
cHao

1
У java нет встроенной вещи для этого? Я действительно предпочел бы делать это в абстрактном паттерне, а не реализовывать цикл for для каждого события.
Томаш Зато - Восстановить Монику


21

Есть 3 различных способа настроить это:

  1. Thrower Внутри Catcher
  2. Catcher Внутри Thrower
  3. Throwerи Catcherвнутри другого класса в этом примереTest

ПРИМЕР РАБОЧЕГО GITHUB I CITING По умолчанию используется вариант 3, чтобы попробовать остальные, просто раскомментируйтеOptionalблок кода "" класса, которым вы хотите быть основным, и установите этот класс в качестве${Main-Class}переменной вbuild.xmlфайле:

4 Вещи, необходимые для бросания кода стороны:

import java.util.*;//import of java.util.event

//Declaration of the event's interface type, OR import of the interface,
//OR declared somewhere else in the package
interface ThrowListener {
    public void Catch();
}
/*_____________________________________________________________*/class Thrower {
//list of catchers & corresponding function to add/remove them in the list
    List<ThrowListener> listeners = new ArrayList<ThrowListener>();
    public void addThrowListener(ThrowListener toAdd){ listeners.add(toAdd); }
    //Set of functions that Throw Events.
        public void Throw(){ for (ThrowListener hl : listeners) hl.Catch();
            System.out.println("Something thrown");
        }
////Optional: 2 things to send events to a class that is a member of the current class
. . . go to github link to see this code . . .
}

2 Вещи, необходимые в файле класса для получения событий из класса

/*_______________________________________________________________*/class Catcher
implements ThrowListener {//implement added to class
//Set of @Override functions that Catch Events
    @Override public void Catch() {
        System.out.println("I caught something!!");
    }
////Optional: 2 things to receive events from a class that is a member of the current class
. . . go to github link to see this code . . .
}

6
@GlassGhost: проблема в том, что mainон статический, а thisв статической функции такого нет . Вам нужно создать new Catcher1()где-нибудь и передать этот экземпляр вместо. 1.5 также не допускается thisв статическом контексте; Я уверен, что это никогда не было разрешено.
Чао

6
@GlassGhost: код, который используется thisв конструкторе, а не в main. Вот почему это работает. Переместите его main, и я гарантирую, что не будет. Это то, что люди пытаются вам сказать, и что ваш ответ пытается сделать. Мне наплевать, что на github - мне все равно, что на SO. А то, что у тебя на ТА, сломано.
Чао

7
@GlassGhost: я не думаю, что ваш ответ в целом неадекватен. Проблема я вижу с ним в том , что код не будет работать как это - вы пытаетесь использовать thisс main, который не будет компилироваться в любой выпущенной версии Java. Если бы эта часть была в конструкторе, или если она была mainсоздана new Catcher1()и использовала ее вместо this, она должна работать, даже в 1.6+.
Цао

6
@GlassGhost: "Объявленный метод staticназывается методом класса. Метод класса всегда вызывается без ссылки на конкретный объект. Попытка обратиться к текущему объекту с помощью ключевого слова thisили ключевого слова superили для ссылки на параметры типа любого окружения объявление в теле метода класса приводит к ошибке времени компиляции. " - JLS для Java 5, §8.4.3.2
cHao

31
Это один из самых странных стилей кода, которые я когда-либо видел
Eric

4

Следующее не совсем то же самое, но похоже, я искал фрагмент, чтобы добавить вызов метода интерфейса, но нашел этот вопрос, поэтому я решил добавить этот фрагмент для тех, кто искал его, как я, и нашел этот вопрос. :

 public class MyClass
 {
        //... class code goes here

        public interface DataLoadFinishedListener {
            public void onDataLoadFinishedListener(int data_type);
        }

        private DataLoadFinishedListener m_lDataLoadFinished;

        public void setDataLoadFinishedListener(DataLoadFinishedListener dlf){
            this.m_lDataLoadFinished = dlf;
        }



        private void someOtherMethodOfMyClass()
        {
            m_lDataLoadFinished.onDataLoadFinishedListener(1);
        }    
    }

Использование заключается в следующем:

myClassObj.setDataLoadFinishedListener(new MyClass.DataLoadFinishedListener() {
            @Override
            public void onDataLoadFinishedListener(int data_type) {
                }
            });
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.