Come posso eseguire una callback JAVA tra le classi?

Vengo da JavaScript, in cui i callback sono piuttosto semplici. Sto cercando di implementarli in JAVA, senza successo.

Ho una class genitore:

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

Poi ho una class figlia, che viene chiamata dal genitore:

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

Qual è il modo giusto di implementare il

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

parte, nella class Genitore, che non è chiaramente corretta?

Definire un’interfaccia e implementarla nella class che riceverà la richiamata.

Fai attenzione alla multi-threading nel tuo caso.

Esempio di codice da 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 classs that have the implementation of CallBack interface caller.register(callBack); } } 

Nel tuo caso, oltre al multi-threading potresti fare così:

 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

Ricorda che questo non gestisce il multi-threading, questo è un altro argomento e può avere varie soluzioni a seconda del progetto.

Il modello osservatore

Il modello di osservatore fa quasi questo, la differenza principale è l’uso di un ArrayList per aggiungere più di un ascoltatore. Dove questo non è necessario, ottieni prestazioni migliori con un riferimento.

Usa il modello di osservatore. Funziona così:

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

Crei un’interfaccia con uno o più metodi da chiamare quando si verifica un evento. Quindi, qualsiasi class che deve essere notificata quando si verificano eventi implementa questa interfaccia.

Ciò consente una maggiore flessibilità, in quanto il produttore è solo a conoscenza dell’interfaccia listener e non di un’implementazione particolare dell’interfaccia listener.

Nel mio esempio:

MyClass è il produttore qui come la sua notifica di un elenco di ascoltatori.

MyListener è l’interfaccia.

MyForm è interessato a somethingHappened , quindi implementa MyListener e si registra con MyClass . Ora MyClass può informare MyForm sugli eventi senza fare riferimento direttamente a MyForm . Questa è la forza del modello di osservatore, riduce la dipendenza e aumenta la riusabilità.

IMO, dovresti dare un’occhiata al pattern Observer , ed è così che funziona la maggior parte degli ascoltatori

Non so se questo è ciò che stai cercando, ma puoi ottenere questo passando una callback alla class child.

per prima cosa definire un callback generico:

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

creare una nuova istanza ITypedCallback nell’istanza di ServerConnections:

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

chiama il metodo execute sull’object 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: Non ho controllato se è corretto al 100%, lo ho codificato direttamente qui.

In questo caso particolare, il seguente dovrebbe funzionare:

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

È una sottoclass anonima.