Utwórz niestandardowe zdarzenie w Javie

193

Chcę zrobić coś takiego w Javie, ale nie znam sposobu:

Kiedy zdarza się zdarzenie „obiekt 1 mówi„ cześć ””, wówczas obiekt 2 reaguje na to zdarzenie, mówiąc „cześć”.

Czy ktoś może mi dać podpowiedź lub przykładowy kod?

conmadoi
źródło

Odpowiedzi:

421

Prawdopodobnie chcesz przyjrzeć się wzorowi obserwatora .

Oto przykładowy kod na początek:

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

Artykuł pokrewny: Java: Tworzenie niestandardowego zdarzenia

aioobe
źródło
Czy istnieje uzasadniony powód, dla którego stackoverflow.com/suggested-edits/237242 nie został przesłany? Pokazuje, jak to zrobić z 2 klasami, jak pierwotnie zadano pytanie.
GlassGhost
2
Co się stanie, jeśli wiele wątków generuje zdarzenia źródłowe, czy będzie to odpowiednio synchronizowane?
Mike G
Zależy od syracji. Każdy słuchacz zostanie powiadomiony zgodnie z zamówieniem, które zarejestrował. (Przy okazji, nie rozumiem, co masz na myśli przez wiele wątków tutaj. Kod nasłuchującego zostanie wydany w tym samym wątku, który spowodował zdarzenie).
aioobe,
8
@GlassGhost: Zostało odrzucone, ponieważ było to w zasadzie całkowite przepisanie. Zmiany w odpowiedziach innych osób są dobre, jeśli naprawią literówki i formatowanie oraz zepsute linki itp., Ale nie powinny radykalnie zmieniać treści. (Niektóre wyjątki dotyczą postów oznaczonych jako „wiki społeczności”.)
cHao
1
Czy java nie ma do tego wbudowanej rzeczy? Naprawdę wolałbym robić to w abstrakcyjny sposób, a nie implementować pętli dla każdego zdarzenia.
Tomáš Zato - Przywróć Monikę
21

Istnieją 3 różne sposoby skonfigurowania tego:

  1. Thrower wnętrze Catcher
  2. Catcher wnętrze Thrower
  3. Throweri Catcherwewnątrz innej klasy w tym przykładzieTest

PRZYKŁAD GITHUBA PRACY JESTEM CITING Domyślnie opcja 3, aby wypróbować inne, po prostu odkomentujOptionalblok kodu klasy, którą chcesz być głównym, i ustaw tę klasę jako${Main-Class}zmienną wbuild.xmlpliku:

4 rzeczy potrzebne do rzucenia bocznego kodu:

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 Rzeczy potrzebne w pliku klasy, aby otrzymywać zdarzenia z klasy

/*_______________________________________________________________*/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
źródło
6
@GlassGhost: Problem polega na tym, że mainjest statyczny i nie ma czegoś takiego jak thisfunkcja statyczna. Musisz new Catcher1()gdzieś utworzyć i przekazać tę instancję. 1.5 także nie pozwalał thisw kontekście statycznym; jestem prawie pewien, że nigdy nie było dozwolone.
cHao
6
@GlassGhost: używany kod thisznajduje się w konstruktorze, a nie w main. Właśnie dlatego to działa. Przenieś do main, a gwarantuję, że nie. To właśnie ludzie próbują ci powiedzieć i jak stara się zrobić twoja odpowiedź. Nie obchodzi mnie, co jest na githubie - obchodzi mnie, co jest na SO. A to, co masz na SO, jest zepsute.
cHao
7
@GlassGhost: Nie sądzę, aby twoja odpowiedź była ogólnie nieodpowiednia. Problem widzę w nim jest to, że kod nie będzie działać jak jest - starasz się używać thisz main, które nie będą w żaden kompilacji wydanej wersji Java. Jeśli ta część znajdowała się w konstruktorze, lub jeśli została mainutworzona new Catcher1()i używana zamiast thisniej, powinna działać, nawet w wersji 1.6+.
cHao
6
@GlassGhost: „Zadeklarowana metoda staticnazywana jest metodą klasową. Metoda klasowa jest zawsze wywoływana bez odniesienia do konkretnego obiektu. Próba odwołania się do bieżącego obiektu za pomocą słowa kluczowego thislub słowa kluczowego superlub odniesienia parametrów parametrów dowolnego otoczenia deklaracja w treści metody klasy powoduje błąd czasu kompilacji. ” - JLS dla Java 5, § 8.4.3.2
cHao
31
To jeden z najdziwniejszych stylów kodu, jaki kiedykolwiek widziałem
Eric,
4

Poniższe informacje nie są dokładnie takie same, ale podobne. Szukałem fragmentu kodu, aby dodać wywołanie do metody interfejsu, ale znalazłem to pytanie, więc zdecydowałem się dodać ten fragment dla osób, które szukają go jak ja, i znalazłem to pytanie. :

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

Użycie jest następujące:

myClassObj.setDataLoadFinishedListener(new MyClass.DataLoadFinishedListener() {
            @Override
            public void onDataLoadFinishedListener(int data_type) {
                }
            });
Ivan
źródło