Как выполнить обратный вызов JAVA между классами?
Я исхожу из JavaScript, в котором обратные вызовы довольно просты. Я пытаюсь реализовать их в JAVA без успеха.
У меня есть родительский класс:
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Server {
ExecutorService workers = Executors.newFixedThreadPool(10);
private ServerConnections serverConnectionHandler;
public Server(int _address) {
System.out.println("Starting Server...");
serverConnectionHandler = new ServerConnections(_address);
serverConnectionHandler.newConnection = function(Socket _socket) {
System.out.println("A function of my child class was called.");
};
workers.execute(serverConnectionHandler);
System.out.println("Do something else...");
}
}
Затем у меня есть дочерний класс, который вызывается из родителя:
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.logging.Level;
import java.util.logging.Logger;
public class ServerConnections implements Runnable {
private int serverPort;
private ServerSocket mainSocket;
public ServerConnections(int _serverPort) {
serverPort = _serverPort;
}
@Override
public void run() {
System.out.println("Starting Server Thread...");
try {
mainSocket = new ServerSocket(serverPort);
while (true) {
newConnection(mainSocket.accept());
}
} catch (IOException ex) {
Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
}
}
public void newConnection(Socket _socket) {
}
}
Каков правильный способ реализации
serverConnectionHandler.newConnection = function(Socket _socket) {
System.out.println("A function of my child class was called.");
};
в классе родителя, что явно неверно?
Ответы
Ответ 1
Определите интерфейс и реализуйте его в классе, который получит обратный вызов.
Обратите внимание на многопоточность в вашем случае.
Пример кода из http://cleancodedevelopment-qualityseal.blogspot.com.br/2012/10/understanding-callbacks-with-java.html
interface CallBack {
void methodToCallBack();
}
class CallBackImpl implements CallBack {
public void methodToCallBack() {
System.out.println("I've been called back");
}
}
class Caller {
public void register(CallBack callback) {
callback.methodToCallBack();
}
public static void main(String[] args) {
Caller caller = new Caller();
CallBack callBack = new CallBackImpl();
caller.register(callBack);
}
}
Ответ 2
Используйте шаблон наблюдателя. Он работает следующим образом:
interface MyListener{
void somethingHappened();
}
public class MyForm implements MyListener{
MyClass myClass;
public MyForm(){
this.myClass = new MyClass();
myClass.addListener(this);
}
public void somethingHappened(){
System.out.println("Called me!");
}
}
public class MyClass{
private List<MyListener> listeners = new ArrayList<MyListener>();
public void addListener(MyListener listener) {
listeners.add(listener);
}
void notifySomethingHappened(){
for(MyListener listener : listeners){
listener.somethingHappened();
}
}
}
Вы создаете интерфейс, который имеет один или несколько методов для вызова при возникновении какого-либо события. Затем любой класс, который должен быть уведомлен о событиях, реализует этот интерфейс.
Это обеспечивает большую гибкость, поскольку производитель знает только о интерфейсе слушателя не для конкретной реализации интерфейса слушателя.
В моем примере:
MyClass
является производителем здесь, поскольку он уведомляет список слушателей.
MyListener
- это интерфейс.
MyForm
интересуется, когда somethingHappened
, поэтому он реализует MyListener
и регистрируется с помощью MyClass
. Теперь MyClass
может сообщить MyForm
о событиях без прямого ссылки на MyForm
. Это сила шаблона наблюдателя, он уменьшает зависимость и увеличивает повторное использование.
Ответ 3
IMO, вы должны взглянуть на шаблон наблюдателя, и именно так работают большинство слушателей.
Ответ 4
Я не знаю, это то, что вы ищете, но вы можете добиться этого, передав обратный вызов дочернему классу.
сначала определите общий обратный вызов:
public interface ITypedCallback<T> {
void execute(T type);
}
создать новый экземпляр ITypedCallback в экземпляре ServerConnections:
public Server(int _address) {
serverConnectionHandler = new ServerConnections(new ITypedCallback<Socket>() {
@Override
public void execute(Socket socket) {
// do something with your socket here
}
});
}
вызвать метод execute в объекте обратного вызова.
public class ServerConnections implements Runnable {
private ITypedCallback<Socket> callback;
public ServerConnections(ITypedCallback<Socket> _callback) {
callback = _callback;
}
@Override
public void run() {
try {
mainSocket = new ServerSocket(serverPort);
while (true) {
callback.execute(mainSocket.accept());
}
} catch (IOException ex) {
Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
btw: я не проверял, правильно ли он на 100%, прямо закодировал его здесь.
Ответ 5
В этом конкретном случае должно работать следующее:
serverConnectionHandler = new ServerConnections(_address) {
public void newConnection(Socket _socket) {
System.out.println("A function of my child class was called.");
}
};
Это анонимный подкласс.