I am coming from JavaScript, in which callbacks are pretty easy. I am trying to implement them into JAVA, without success.
I have a Parent class:
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...");
}
}
Then I have a child class, that is called from the parent:
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) {
}
}
What is the right way of implementing the
serverConnectionHandler.newConnection = function(Socket _socket) {
System.out.println("A function of my child class was called.");
};
part, in the Parent class, which is clearly not correct?
Define an interface, and implement it in the class that will receive the callback.
Have attention to the multi-threading in your case.
Code example from 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);
}
}
In your case, apart from multi-threading you could do like this:
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
Remember this does not handle multi-threading, this is another topic and can have various solutions depending on the project.
The observer-pattern
The observer-pattern does nearly this, the major difference is the use of an ArrayList
for adding more than one listener. Where this is not needed, you get better performance with one reference.