2016-12-24 20 views
1

この質問には2つの部分があります。コールバックwith java 8

パート1:私はコールバックが必要な理由に完全に明確ではないよ

、なぜ単にオブジェクトを渡すと、例えばコードCに見られるように、メソッドを呼び出すのではなく、インタフェースを作成し、通過しません例えば、コードA、またはB

パート2のように、その中:

ベローズを所定の3つの例示コードの違いは何であり、AとBとの間の差はありますか?パフォーマンスと優れたプラクティスのどちらが最適なのか、またパフォーマンスの向上をもたらすボンネットの下で起こっていること、つまり実用性の面で別のものを使用するのがベストなのはなぜですか。

のコード例A:

interface Iexample{ 
    void foo(); 
} 

public class Roo implements Iexample{ 
    public void foo(){ 
     System.out.println("hello"); 
    } 
} 

public class Too{ 

    public void eoo(Iexample callback){ 
     callback.foo(); 
    } 

    public static void main(String[] args){ 
     Roo roo = new Roo(); 
     Too too = new Too(); 

     too.eoo(roo::foo); 
    } 
} 

サンプルコードB(本体のみが異なる):

interface Iexample{ 
    void foo(); 
} 

public class Roo implements Iexample{ 
    public void foo(){ 
     System.out.println("hello"); 
    } 
} 

public class Too{ 
    public void eoo(Iexample callback){ 
     callback.foo(); 
    } 

    public static void main(String[] args){ 
     Roo roo = new Roo(); 
     Too too = new Too(); 

     too.eoo(roo); 
    } 
} 

コード例C

public class Roo { 
    public void foo(){ 
     System.out.println("hello"); 
    } 
} 

public class Too{ 
    public void eoo(Roo callback){ 
     callback.foo(); 
    } 

    public static void main(String[] args){ 
     Roo roo = new Roo(); 
     Too too = new Too(); 

     too.eoo(roo); 
    } 
} 

編集:誰でもなぜ説明する気にdownvotingですか?私が...例Aで、あなたのRooクラスがIexampleを実装する必要がないことを

+0

なぜ私はあなたがインターフェイスを実装する必要があるコールバックを使用するのかと尋ねています。私が3つすべてで示したように、先ほどやったときに別のオブジェクトにオブジェクトを渡すことができますのコード例。最初の1つは、インターフェイス(とJava 8のメソッド参照)を使用し、2番目は同じですが、オブジェクトを渡します.3番目はインタフェースをまったく使用しません。あなたが完全にそれを避けることができるとき、なぜコールバックを使うのですか?明らかに私は何かを理解していないので、その違いが何であるか尋ねていたのです。私は例を挙げた。 – James

+0

申し訳ありません - あなたの言葉通り、第1部の内容を理解するために第2部を読んでいたことは明らかではありませんでした。それは本当に二部構成の質問ではありません。 – ajb

+0

私は2つの部分は、全体の質問に2つの部分があることを意味したとき、私はそれを分割すると対処しやすくなると思った。私はそれをもっと明確にしておくべきだった。 – James

答えて

1

あなたの例では、コールバックは必要ありませんが、コードの意図に依存します。

コールバックの点では、おそらくあなたのコードで意味されていたのはCommand Patternでした。 Java 8より前では、CまたはC++のような関数ポインタがサポートされていなかったので、関数を引数として渡すことはできませんでした。回避策は、コマンド・パターンです。ここでは、クラス内で関数呼び出しをラップし、その関数を呼び出すことのできるクラスを渡します。あなたの例では、インターフェイスIexampleは、引数または戻り値なしのメソッドfooのラッパーを定義しています。

次の例を考えます。バックグラウンドワーカーが何か他のものを計算する間、GUIや何かを表示するメインメソッドがあります。現在の進捗状況を表示する出力メソッドがありますが、これはメインクラスにあります。今、あなたはどのように機能をワーカーに渡すので、それを使うことができますか?あなたは、コマンドパターンを使用して、このようなメソッドを実行するラッパークラスを実装:

interface ProgressCallback { 
    void progressUpdate(int progress); 
} 

class BackgroundWorker{ 

    private int progress; 
    private ProgressCallback callback; 

    public BackgroundWorker(ProgressCallback progressCallback) { 
     this.callback = progressCallback; 
    } 

    // BackgroundWorker calls to signal the progress 
    // update to your main application, by calling 
    // its method passed through the callback wrapper 
    // class ProgressCallback. 
    private void notifyProgressUpdateToMain() { 
     callback.progressUpdate(progress); 
    } 

    // Awesome stuff implemented here 

} 

class Main { 

    public static void main(String[] args) { 

     // Implement a new callback "on-the-fly" with the interface 
     // as template for a progress callback. 
     ProgressUpdate callback = new ProgressUpdate(int progress) { 
      @Override 
      public void progressUpdate() { 
       // The call of the method of this main class 
       // is now encapsulated in the callback 
       setProgressUpdate(progress); 
      } 
     }; 

     // Does awesome stuff in background 
     BackgroundWorker worker = new BackgroudWorker(callback); 
     worker.start(); 

     // Do other stuff, while the worker sets the progress 

    } 

    private setProgressUpdate(int progress) { 
     // Magically retrieved progress bar from the GUI 
     progressBar.setProgress(progress); 
    } 

} 

あなたの最初の例は、単に匿名のラッパークラスを作成することにより、パラメータとしてメソッドfoo()を渡すために、新しいJava 8演算子::を使用しています。 2番目の例は、以前のバージョンでも使用できます。上記の例のように、インタフェースを使用すると、さまざまなコールバックを簡単に実装できます。 3番目の例では、単一のクラスRooしか実装できず、サブクラス化しかできないので、ここで達成したいものに合わないため、この柔軟性は得られません。

1

注意私が間違っていた知っていた場合にはより多くの情報を追加して幸せだし、それはそのメソッドfooを呼び出す必要はありません。パラメータを持たないvoidメソッドであれば、任意のメソッドをeooに渡すことができます。この場合、implements Iexampleをコードに追加すると、実際にはインターフェイスを実装しているということはあなたのコードでは実際には使用されないため、この問題は不明瞭になる可能性があります。

AとB(およびC)の選択は、主に概念的です。あなたは何を伝えようとしていますか?これは無意味な名前のクラスやメソッドがあるときに見えにくいものです。インタフェースとそのインタフェースを実装するクラスを定義することは、抽象クラスを拡張することに似ています。抽象基本クラスを定義し、そのクラスを実装するものが1つ以上のメソッドの具体的な実装を提供すると言っています。基本的に、クラス間の「is-a」関係を定義しています。

コールバックを使用するほうが、他のメソッドをパラメータとして使用するメソッドを作成し、クラスの関係を定義したくない場合に適しています。例えば、一般化されたΣを数学的に行う関数、つまり与えられた範囲内のあるインデックスの関数の値を合計する関数を記述したいとします。私の関数は、パラメータとして別の関数、すなわち合計したいものを取る必要があります。intをパラメータとして返して、たとえばdoubleを返します。しかし、新しいクラスはありません - 私はただそれが任意の機能を取るようにしたい。これは、機能的なインターフェイスとコールバックを使いたい場合です。

注あなたの例ではA、方法

public void eoo(Iexample callback){ 

は、パラメータ、Iexampleを実装するオブジェクトとして、持っていなければならないこと。あなたは

too.eoo(roo::foo); 

とそれを呼び出すときしかし渡されるオブジェクトは、ないクラスRooの対象ではなく、特別にちょうどroo::fooを渡すために、コンパイラによって作成された匿名クラスです。

+0

さて、なぜ私は混乱しているのか理解し始めていると思います。私は、(例えば、B)eooがタイプIexampleのパラメータを探していたと考えています。つまり、foo()メソッド(Iexampleを実装しています)を持つオブジェクトのみを受け入れます。私はもう少し理解し始めています。 – James

+0

私は混乱していました。なぜなら、Java 8では::がメソッド参照演算子であり、明らかに(例えばA) 'too.eoo(roo :: foo);です。有効だったと私はそれがインターフェイスを実装するオブジェクトを探していたと思った。 – James

関連する問題