Tạo một sự kiện tùy chỉnh trong Java


193

Tôi muốn làm một cái gì đó như thế này trong Java nhưng tôi không biết cách:

Khi sự kiện "đối tượng 1 nói 'xin chào'" xảy ra, thì đối tượng 2 sẽ phản hồi lại sự kiện đó bằng cách nói "xin chào".

Ai đó có thể cho tôi một gợi ý hoặc mã mẫu?



Câu trả lời:


421

Bạn có thể muốn nhìn vào mô hình quan sát viên .

Đây là một số mã mẫu để tự bắt đầu:

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

Bài viết liên quan: Java: Tạo một sự kiện tùy chỉnh


Có một lý do hợp pháp stackoverflow.com/suggested-edits/237242 không đi qua? Nó cho thấy làm thế nào để làm điều này với 2 lớp như câu hỏi ban đầu được hỏi.
GlassGhost

2
Điều gì xảy ra nếu nhiều luồng đang tạo các sự kiện nguồn, điều này có được đồng bộ hóa đúng không?
Mike G

Phụ thuộc vào sự đánh giá. Mỗi người nghe sẽ được thông báo theo thứ tự họ đã đăng ký. (Btw, tôi không hiểu ý của bạn về nhiều chủ đề ở đây. Mã người nghe sẽ được sử dụng trên cùng một chủ đề khiến sự kiện xảy ra.)
aioobe

8
@GlassGhost: Nó đã bị từ chối vì về cơ bản nó là một bản viết lại hoàn toàn. Chỉnh sửa câu trả lời của người khác là tốt nếu họ sửa lỗi chính tả và định dạng và các liên kết bị hỏng, nhưng họ không nên thay đổi hoàn toàn nội dung. (Một số trường hợp ngoại lệ áp dụng cho các bài đăng được đánh dấu "wiki cộng đồng".)
cHao

1
Có java không được xây dựng trong điều này? Tôi thực sự thích làm điều này trong mô hình trừu tượng, không thực hiện vòng lặp cho mọi sự kiện.
Tomáš Zato - Phục hồi Monica


21

Có 3 cách khác nhau mà bạn có thể muốn thiết lập:

  1. Thrower bên trong của Catcher
  2. Catcher bên trong của Thrower
  3. ThrowerCatcherbên trong một lớp khác trong ví dụ nàyTest

VÍ DỤ GITHUB LÀM VIỆC TÔI ĐANG TẠO Mặc định cho Tùy chọn 3, để thử các khối khác chỉ đơn giản là bỏ quaOptionalkhối mã "" của lớp bạn muốn là chính và đặt lớp đó làm${Main-Class}biến trongbuild.xmltệp:

4 điều cần thiết khi ném mã bên:

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 Điều cần thiết trong một tệp lớp để nhận các sự kiện từ một lớp

/*_______________________________________________________________*/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: Vấn đề là ở dạng maintĩnh và không có thischức năng nào giống như trong hàm tĩnh. Bạn cần tạo một new Catcher1()nơi nào đó và thay vào đó vượt qua trường hợp đó. 1,5 không cho phép thistrong một bối cảnh tĩnh; Tôi khá chắc chắn rằng nó chưa bao giờ được cho phép.
cHao

6
@GlassGhost: Mã sử ​​dụng thislà trong một hàm tạo, không phải trong main. Đó là lý do tại sao nó hoạt động. Di chuyển nó đến main, và tôi đảm bảo nó sẽ không. Đó là những gì mọi người đã cố gắng nói với bạn, và câu trả lời của bạn đang cố gắng làm gì. Tôi không cho những gì chết tiệt trên github - tôi quan tâm những gì trên SO. Và những gì bạn có trên SO bị phá vỡ.
cHao

7
@GlassGhost: Tôi không nghĩ rằng câu trả lời của bạn không đầy đủ. Vấn đề tôi thấy với nó là mã sẽ không hoạt động như hiện tại - bạn đang cố gắng sử dụng thistừ mainđó, nó sẽ không được biên dịch trong bất kỳ phiên bản Java được phát hành nào. Nếu phần đó nằm trong một hàm tạo thay thế, hoặc nếu mainđược tạo new Catcher1()và sử dụng nó thay vì this, nó sẽ hoạt động, ngay cả trong 1.6+.
cHao

6
@GlassGhost: "Một phương thức được khai báo staticđược gọi là phương thức lớp. Phương thức lớp luôn được gọi mà không tham chiếu đến một đối tượng cụ thể. Cố gắng tham chiếu đối tượng hiện tại bằng cách sử dụng từ khóa thishoặc từ khóa superhoặc để tham chiếu các tham số loại của bất kỳ xung quanh khai báo trong phần thân của một phương thức lớp dẫn đến lỗi thời gian biên dịch. " - JLS cho Java 5, §8.4.3.2
cHao

31
Đây là một trong những kiểu mã kỳ lạ nhất tôi từng thấy
Eric

4

Phần sau đây không hoàn toàn giống nhau nhưng tương tự, tôi đã tìm kiếm một đoạn để thêm một cuộc gọi vào phương thức giao diện, nhưng tìm thấy câu hỏi này, vì vậy tôi đã quyết định thêm đoạn trích này cho những người đang tìm kiếm nó như tôi và tìm thấy câu hỏi này :

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

Cách sử dụng như sau:

myClassObj.setDataLoadFinishedListener(new MyClass.DataLoadFinishedListener() {
            @Override
            public void onDataLoadFinishedListener(int data_type) {
                }
            });
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.