コールバックが非常に簡単な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.");
};
一部、親クラスでは、明らかに正しくありませんか?
インターフェイスを定義し、コールバックを受け取るクラスに実装します。
ケースのマルチスレッドに注意してください。
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);
}
}
あなたの場合、マルチスレッドとは別に、次のようにすることができます:
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);
}
}
}
マルチスレッド
これはマルチスレッドを処理しないことを忘れないでください。これは別のトピックであり、プロジェクトに応じてさまざまな解決策があります。
オブザーバーパターン
オブザーバーパターンはほぼこれを行います。主な違いは、複数のリスナーを追加するためのArrayList
の使用です。これが不要な場合は、1つのリファレンスでパフォーマンスが向上します。
オブザーバーパターンを使用します。それはこのように動作します:
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();
}
}
}
何らかのイベントが発生したときに呼び出される1つ以上のメソッドを持つインターフェイスを作成します。次に、イベントが発生したときに通知する必要があるクラスは、このインターフェイスを実装します。
これにより、プロデューサはリスナーインターフェースのみを認識するため、柔軟性が高まります。notリスナーインターフェースの特定の実装です。
私の例では:
MyClass
は、リスナーのリストを通知するプロデューサーです。
MyListener
はインターフェースです。
MyForm
はsomethingHappened
のときに関心があるため、MyListener
を実装し、MyClass
に登録しています。 MyClass
は、MyForm
を直接参照することなく、イベントについてMyForm
に通知できるようになりました。これがオブザーバーパターンの強さであり、依存関係を減らして再利用性を高めます。
IMO、 Observer Pattern をご覧ください。これがほとんどのリスナーの動作です
これがあなたが探しているものかどうかはわかりませんが、子クラスにコールバックを渡すことでこれを達成できます。
最初に一般的なコールバックを定義します:
public interface ITypedCallback<T> {
void execute(T type);
}
serverConnectionsインスタンス化で新しいITypedCallbackインスタンスを作成します。
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%正しいかどうかはチェックせず、ここに直接コーディングしました。
この特定のケースでは、以下が機能するはずです。
serverConnectionHandler = new ServerConnections(_address) {
public void newConnection(Socket _socket) {
System.out.println("A function of my child class was called.");
}
};
これは匿名サブクラスです。