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

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

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

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

6 ответов

Решение

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

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

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: Создание пользовательского события

То, что вы хотите, это реализация шаблона наблюдателя. Вы можете сделать это самостоятельно полностью или использовать Java-классы, такие как java.util.Observer а также java.util.Observable

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

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

ПРИМЕР РАБОЧЕГО ГИТУБА 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 . . .
}

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

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

Терминология

  • слушатели - наблюдатели / обработчики
  • диспетчер - контейнер субъекта / наблюдателя

Обычно, когда люди реализуют шаблон наблюдателя , они требуют, чтобы диспетчер существовал, прежде чем какой-либо слушатель сможет на него подписаться. Но есть способ получше - сигналы .

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

      interface Chat{
    void onNewMessage(String s);    
}

class Foo{
    Signal<Chat> chatSignal = Signals.signal(Chat.class);
    
    void bar(){
        chatSignal.addListener( s-> Log.d("chat", s) ); // logs all the messaged to Logcat
    }
}

class Foo2{
    Signal<Chat> chatSignal = Signals.signal(Chat.class);
    
    void bar2(){
        chatSignal.dispatcher.onNewMessage("Hello from Foo2"); // dispatches "Hello from Foo2" message to all the listeners
    }
}

В этом примере сигнал автоматически создается из Chatинтерфейс. Это позволяет Foo зарегистрироваться для этого и Foo2 отправлять новые сообщения без взаимодействия.

Отказ от ответственности: я являюсь автором сигналов.

Кхм, мне недавно нужно было делать мероприятия и я наткнулся на эту тему. Решил добавить свою реализацию на основе C# версии событий, может кто прочитает и ему будет полезно:

      @FunctionalInterface
public interface Action{
    void accept(Object... args);
}

public class CustomEvent {

    protected List<Action> listeners = new ArrayList<>();

    public void addListener(Action arg0){
        listeners.add(arg0);
    }

    public void removeListener(Action arg0){
        listeners.remove(arg0);
    }

    public void invoke(Object... args){
        for (Action listener : listeners) {
            listener.accept(args);
        }
    }
}

public class Example1 {
    public CustomEvent onValueChanged;
    
    private void doSomething(){
        onValueChanged.invoke(); // or .invoke(arg0, arg1, ...)
    }
}

public class Example2 {
    private Example1 example1;
    private Action linkToAction;
    private void init(){
        example1 = new Example1();
        linkToAction = args -> {
            doSomethingAnother(); // or doSomethingAnother((Type)args[0], (Type)args[1], ...)
        }
        example1.onValueChanged.addListener(linkToAction);
    }
    
    public void doSomethingAnother(){}
    
    public void unsubscribe(){
        example1.onValueChanged.removeListener(linkToAction);
    }
}

Это простой пример, реализация интерфейса Action, которую я сделал, основана на интерфейсе Consumer , поэтому имена методов похожи, но вы также можете изменить его.

Другие вопросы по тегам