2013-08-16 6 views
38

私はJavaScriptから来ており、コールバックはかなり簡単です。私はそれらをJavaに実装しようとしていますが、成功することはありません。クラス間で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."); 
}; 

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

+1

コマンドパターン。 –

+0

参照:http://stackoverflow.com/a/4685606/483588 –

答えて

81

は、インターフェイスを定義し、コールバックを受け取ることになりますクラスでそれを実装する仕組みです。

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

コード例離れて、あなたはこのように行うことができますマルチスレッドから、あなたの場合は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つのリファレンスでより良いパフォーマンスを得ることができます。

+2

インターフェイスのポイントは何ですか? 'CallBackImpl'は、インターフェイスを実装せずに、それ自身のクラスにならないのはなぜですか? – CodyBugstein

+9

@Imrayインターフェイスを使用することで、CallBackを実装するクラスを呼び出し側に登録する柔軟性が得られます。それは単なるCallBackImplである必要はありません。 – crysis

+0

これはシングルスレッドでブロックされませんか?異なるスレッドからのコールバックの例は何でしょうか? –

6

IMO、あなたはObserver Patternを見ている必要があり、これは、リスナーのほとんどが

43

オブザーバーパターンを使用します。これは次のように機能します。

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つ以上あるインターフェイスを作成します。次に、イベントが発生したときに通知を受ける必要があるすべてのクラスが、このインタフェースを実装します。

これにより、プロデューサはリスナーインターフェイスの特定の実装であるではなく、であることを認識します。私の例では

MyClassはここにそのリスナーのリストを通知するなどのプロデューサーです。

MyListenerはインターフェイスです。

MyFormはときsomethingHappenedに興味があるので、MyListenerを実装し、MyClassで自身を登録しています。今すぐMyClassMyFormを直接参照せずにイベントについてMyFormに通知できます。これはオブザーバパターンの強さであり、依存性を減らし、再利用性を向上させます。

+3

すてきな説明、すべての回答とインターネット上のその基本的な例のうち、私はあなたの説明からコールバックの使用を理解しました..素晴らしい答え(Y) – Bawa

+0

私はあなたがMyClassのインスタンスを作成している理由を理解していませんMyFormの内部コンストラクターです。ボディーが他の第3クラスのMyClassのインスタンスを作成してaddListenerを呼び出すと、MyFormのインスタンスまたはMyListenerから派生した他のクラスが作成されるためです。 –

+0

いいえ。他のクラスのMyClassのインスタンス上のaddListenerをCalLingしても、MyFormのインスタンスがインスタンス化されることはありません。 MyFormのコンストラクタにMyClassを注入する方が良いかもしれないと私は同意しますが、私は単純な例を保つようにしていましたが、オブザーバパターンに焦点を当てました。 –

3

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

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

コールコールバックオブジェクトにMethodeのを実行します。ServerConnectionsインスタンス化の新しいITypedCallbackインスタンスを作成

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

最初の一般的なコールバックを定義。

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%正確であるかどうかを確認しませんでした。ここに直接コードされています。

+0

どうすれば、コードがより読みやすく、保守しやすいように、インタフェースのメソッドでデフォルトセマンティクスを実装できるのでしょうか? –

+0

申し訳ありませんが、私はあなたの質問を得ることはありません。コールバックインターフェイスを直接インスタンス化するのではなく、コールバック実装を宣言していますか? – 3x14159265

+0

はい、とにかく、それは意見の問題です。 –

0

この特定のケースでは、次のように動作するはずです:

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

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

関連する問題