Создать пользовательское событие в 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 различных способа настроить это:
Thrower
ВнутриCatcher
Catcher
ВнутриThrower
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 , поэтому имена методов похожи, но вы также можете изменить его.