¿Cómo realizo una callback JAVA entre clases?

Vengo de JavaScript, en el que las devoluciones de llamada son bastante fáciles. Estoy tratando de implementarlos en JAVA, sin éxito.

Tengo una clase para padres:

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

Luego tengo una clase para niños, que se llama desde el padre:

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

¿Cuál es la forma correcta de implementar el

 serverConnectionHandler.newConnection = function(Socket _socket) { System.out.println("A function of my child class was called."); }; 

parte, en la clase de Padres, que claramente no es correcto?

Defina una interfaz e impleméntela en la clase que recibirá la callback.

Preste atención al multihilo en su caso.

Ejemplo de código de http://cleancodedevelopment-qualityseal.blogspot.com.br/2012/10/understanding-callbacks-with-java.html

 interface CallBack { //declare an interface with the callback methods, so you can use on more than one class and just refer to the interface void methodToCallBack(); } class CallBackImpl implements CallBack { //class that implements the method to callback defined in the interface 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(); //because of the interface, the type is Callback even thought the new instance is the CallBackImpl class. This alows to pass different types of classes that have the implementation of CallBack interface caller.register(callBack); } } 

En su caso, además de multi-threading, podría hacer esto:

 interface ServerInterface { void newSeverConnection(Socket socket); } public class Server implements ServerInterface { public Server(int _address) { System.out.println("Starting Server..."); serverConnectionHandler = new ServerConnections(_address, this); workers.execute(serverConnectionHandler); System.out.println("Do something else..."); } void newServerConnection(Socket socket) { System.out.println("A function of my child class was called."); } } public class ServerConnections implements Runnable { private ServerInterface serverInterface; public ServerConnections(int _serverPort, ServerInterface _serverInterface) { serverPort = _serverPort; serverInterface = _serverInterface; } @Override public void run() { System.out.println("Starting Server Thread..."); if (serverInterface == null) { System.out.println("Server Thread error: callback null"); } try { mainSocket = new ServerSocket(serverPort); while (true) { serverInterface.newServerConnection(mainSocket.accept()); } } catch (IOException ex) { Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex); } } } 

Multi-threading

Recuerde que esto no maneja el multi-threading, este es otro tema y puede tener varias soluciones dependiendo del proyecto.

El patrón de observador

El patrón de observación hace casi esto, la principal diferencia es el uso de una ArrayList para agregar más de un oyente. Donde esto no es necesario, obtienes un mejor rendimiento con una referencia.

Usa el patrón de observador. Funciona así:

 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 listeners = new ArrayList(); public void addListener(MyListener listener) { listeners.add(listener); } void notifySomethingHappened(){ for(MyListener listener : listeners){ listener.somethingHappened(); } } } 

Usted crea una interfaz que tiene uno o más métodos para llamar cuando ocurre algún evento. Entonces, cualquier clase que necesita ser notificada cuando ocurren eventos implementa esta interfaz.

Esto permite más flexibilidad, ya que el productor solo conoce la interfaz del oyente, no una implementación particular de la interfaz del oyente.

En mi ejemplo:

MyClass es el productor aquí al notificar una lista de oyentes.

MyListener es la interfaz.

MyForm está interesado en cuando somethingHappened MyListener , por lo que está implementando MyListener y registrándose con MyClass . Ahora MyClass puede informar a MyForm sobre eventos sin hacer referencia directa a MyForm . Esta es la fuerza del patrón del observador, reduce la dependencia y aumenta la reutilización.

OMI, debería echarle un vistazo al Patrón de Observador , y así es como trabajan la mayoría de los oyentes

No sé si esto es lo que estás buscando, pero puedes lograrlo pasando una callback a la clase infantil.

primero defina una callback genérica:

 public interface ITypedCallback { void execute(T type); } 

crear una nueva instancia de ITypedCallback en la instanciación de ServerConnections:

 public Server(int _address) { serverConnectionHandler = new ServerConnections(new ITypedCallback() { @Override public void execute(Socket socket) { // do something with your socket here } }); } 

llama al método de ejecución en el objeto de callback.

 public class ServerConnections implements Runnable { private ITypedCallback callback; public ServerConnections(ITypedCallback _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: No revisé si es 100% correcto, aquí lo codifiqué directamente.

En este caso particular, lo siguiente debería funcionar:

 serverConnectionHandler = new ServerConnections(_address) { public void newConnection(Socket _socket) { System.out.println("A function of my child class was called."); } }; 

Es una subclase anónima.