web-dev-qa-db-ja.com

クラス間で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.");
};

一部、親クラスでは、明らかに正しくありませんか?

59
Ágota Horváth

インターフェイスを定義し、コールバックを受け取るクラスに実装します。

ケースのマルチスレッドに注意してください。

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

あなたの場合、マルチスレッドとは別に、次のようにすることができます:

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つのリファレンスでパフォーマンスが向上します。

114

オブザーバーパターンを使用します。それはこのように動作します:

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はインターフェースです。

MyFormsomethingHappenedのときに関心があるため、MyListenerを実装し、MyClassに登録しています。 MyClassは、MyFormを直接参照することなく、イベントについてMyFormに通知できるようになりました。これがオブザーバーパターンの強さであり、依存関係を減らして再利用性を高めます。

56

IMO、 Observer Pattern をご覧ください。これがほとんどのリスナーの動作です

6
sanbhat

これがあなたが探しているものかどうかはわかりませんが、子クラスにコールバックを渡すことでこれを達成できます。

最初に一般的なコールバックを定義します:

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%正しいかどうかはチェックせず、ここに直接コーディングしました。

3
pichsenmeister

この特定のケースでは、以下が機能するはずです。

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

これは匿名サブクラスです。

0
akkerman