Erstellen Sie ein benutzerdefiniertes Ereignis in Java

Antworten:

421

Sie möchten wahrscheinlich das Beobachtermuster untersuchen .

Hier ist ein Beispielcode, mit dem Sie beginnen können:

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..."
    }
}

In Verbindung stehender Artikel: Java: Erstellen eines benutzerdefinierten Ereignisses

aioobe
quelle
Gibt es einen legitimen Grund, warum stackoverflow.com/suggested-edits/237242 nicht durchgegangen ist ? Es zeigt, wie dies mit 2 Klassen als ursprünglich gestellte Frage gemacht wird.
GlassGhost
2
Was passiert, wenn mehrere Threads die Quellereignisse generieren? Wird dies ordnungsgemäß synchronisiert?
Mike G
Kommt auf die Siruation an. Jeder Hörer wird gemäß der von ihm registrierten Reihenfolge benachrichtigt. (Übrigens verstehe ich nicht, was Sie hier mit mehreren Threads meinen. Der Listener-Code wird auf demselben Thread ausgeführt, der das Auftreten des Ereignisses verursacht hat.)
aioobe
8
@GlassGhost: Es wurde abgelehnt, weil es im Grunde ein totales Umschreiben war. Änderungen an der Antwort einer anderen Person sind gut, wenn sie Tippfehler und Formatierungen sowie fehlerhafte Links und dergleichen korrigiert, aber sie sollten den Inhalt nicht radikal ändern. (Einige Ausnahmen gelten für Beiträge mit der Aufschrift "Community-Wiki".)
CHA
1
Hat Java kein eingebautes Ding dafür? Ich würde es wirklich vorziehen, dies in einem abstrakten Muster zu tun und nicht für jedes Ereignis eine for-Schleife zu implementieren.
Tomáš Zato - Wiedereinsetzung Monica
27

Was Sie wollen, ist eine Implementierung des Beobachtermusters . Sie können es komplett selbst machen oder Java-Klassen wie java.util.Observerund verwendenjava.util.Observable

Bozho
quelle
2
Wiederverwendung - Recyceln. Aber werfen Sie
count0
21

Es gibt drei verschiedene Möglichkeiten, wie Sie dies einrichten möchten:

  1. Thrower Innen Catcher
  2. Catcher Innen Thrower
  3. Throwerund Catcherinnerhalb einer anderen Klasse in diesem BeispielTest

DAS ARBEITSGITHUB-BEISPIEL, DAS ICH ZITIERE Standardmäßig wird Option 3 verwendet, um die anderen zu testen , einfach das Kommentar "Optional Codeblock der Klasse aus, die Sie als Hauptklasse verwenden möchten, und legen Sie diese Klasse als ${Main-Class}Variable in der build.xmlDatei fest:

4 Dinge, die beim Werfen von Seitencode benötigt werden:

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 Dinge, die in einer Klassendatei benötigt werden, um Ereignisse von einer Klasse zu empfangen

/*_______________________________________________________________*/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 . . .
}
GlassGhost
quelle
6
@GlassGhost: Das Problem ist, dass maines statisch ist und es keine thisstatische Funktion gibt. Sie müssen new Catcher1()irgendwo eine erstellen und stattdessen diese Instanz übergeben. 1.5 erlaubte auch thisin einem statischen Kontext nicht; Ich bin mir ziemlich sicher, dass es nie erlaubt wurde.
CHao
6
@GlassGhost: Der verwendete Code thisbefindet sich in einem Konstruktor, nicht in main. Deshalb funktioniert es. Bewegen Sie es zu main, und ich garantiere, dass es nicht wird. Das ist es, was die Leute versucht haben, Ihnen zu sagen, und was Ihre Antwort versucht, zu tun. Es ist mir egal, was auf Github läuft - es ist mir egal, was auf SO läuft. Und was Sie auf SO haben, ist kaputt.
CHao
7
@GlassGhost: Ich denke nicht, dass Ihre Antwort insgesamt unzureichend ist. Das Problem , das ich mit ihm zu sehen ist , dass der Code nicht Arbeit wie - Sie versuchen , zu verwenden , thisaus main, die nicht in irgendeiner freigegebenen Version von Java kompilieren. Wenn sich dieser Teil stattdessen in einem Konstruktor befindet oder wenn ein mainerstellt new Catcher1()und stattdessen verwendet wird this, sollte er auch in Version 1.6+ funktionieren.
CHao
6
@GlassGhost: "Eine deklarierte Methode staticwird als Klassenmethode bezeichnet. Eine Klassenmethode wird immer ohne Verweis auf ein bestimmtes Objekt aufgerufen. Es wird versucht, das aktuelle Objekt mit dem Schlüsselwort thisoder dem Schlüsselwort superzu referenzieren oder auf die Typparameter einer Umgebung zu verweisen Die Deklaration im Hauptteil einer Klassenmethode führt zu einem Fehler bei der Kompilierung. " - JLS für Java 5, §8.4.3.2
cHao
31
Dies ist einer der seltsamsten Codestile, die ich je gesehen habe
Eric
4

Das Folgende ist nicht genau dasselbe, aber ähnlich. Ich habe nach einem Snippet gesucht, um einen Aufruf zur Schnittstellenmethode hinzuzufügen, aber diese Frage gefunden. Deshalb habe ich beschlossen, dieses Snippet für diejenigen hinzuzufügen, die wie ich danach gesucht haben und diese Frage gefunden haben ::

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

Die Verwendung ist wie folgt:

myClassObj.setDataLoadFinishedListener(new MyClass.DataLoadFinishedListener() {
            @Override
            public void onDataLoadFinishedListener(int data_type) {
                }
            });
Ivan
quelle