web-dev-qa-db-ja.com

Java)でのデリゲートとコールバック

Javaのデリゲートとコールバックの用語について誤解があります。

class MyDriver {

    public static void main(String[] argv){
        MyObject myObj = new MyObject();
        // definition of HelpCallback omitted for brevity
        myObj.getHelp(new HelpCallback () {
            @Override
            public void call(int result) {
                System.out.println("Help Callback: "+result);
            }
        });
    }
}

class MyObject {

    public void getHelp(HelpCallback callback){
        //do something
        callback.call(OK);
    }
}

コールバックですか、それともデリゲートですか( デリゲートとコールバックは同じですか、類似していますか? )?

次に別のものを実装する方法は?

16
pvllnspk

これはコールバックです。 ウィキペディアによると

コンピュータプログラミングでは、コールバックは、他のコードへの引数として渡される実行可能コードの一部への参照です。

それでは、実行可能コードを見てみましょう。

_public void getHelp(HelpCallback callback){
    //do something
    callback.call(OK);
}
_

ここで、callback引数は、タイプHelpCallbackのオブジェクトへの参照です。その参照は引数として渡されるため、コールバックです。

委任の例

委任は、メソッドの呼び出し方法に関係なく、オブジェクトによって内部的に行われます。たとえば、callback変数が引数ではなく、インスタンス変数だった場合:

_class MyDriver {

    public static void main(String[] argv){
        // definition of HelpStrategy omitted for brevity
        MyObject myObj = new MyObject(new HelpStrategy() {
            @Override
            public void getHelp() {
                System.out.println("Getting help!");
            }
        });
        myObj.getHelp();
    }

}

class MyObject {
    private final HelpStrategy helpStrategy;

    public MyObject(HelpStrategy helpStrategy) {
        this.helpStrategy = helpStrategy;
    }

    public void getHelp(){
        helpStrategy.getHelp();
    }
}
_

...それなら委任になります。

ここで、MyObject戦略パターン を使用します。注意すべき点が2つあります。

  1. getHelp()の呼び出しには、実行可能コードへの参照の受け渡しは含まれません。つまり、これはコールバックではありません。
  2. MyObject.getHelp()helpStrategy.getHelp()を呼び出すという事実は、MyObjectオブジェクトのパブリックインターフェイスまたはgetHelp()の呼び出しからは明らかではありません。この種の 情報隠蔽 は、委任の特徴です。

また、getHelp()メソッドに_// do something_セクションがないことにも注意してください。コールバックを使用する場合、コールバックはオブジェクトの動作に関連することは何もしません。コールバックは何らかの方法で呼び出し元に通知するだけなので、_// do something_セクションが必要でした。ただし、デリゲートを使用する場合、メソッドの実際の動作はデリゲートによって異なります。したがって、それぞれが異なる目的を果たすため、実際には両方が必要になる可能性があります。

_    public void getHelp(HelpCallback callback){
        helpStrategy.getHelp(); // perform logic / behavior; "do something" as some might say
        if(callback != null) {
            callback.call(); // invoke the callback, to notify the caller of something
        }
    }
_
34

「コールバック」は、呼び出しているモジュールに、そのモジュールがコードを呼び出す方法を提供する一般的なパターンの名前であると私は主張します。 AC#デリゲートまたはObjCデリゲートオブジェクト(これら2つは完全に異なる獣です)またはJava class-implementing-the-callback-interfaceは、コールバックを実装するプラットフォーム固有の異なる方法ですパターン。(それら自体もパターンと見なすことができます。)他の言語では、その方法が多少異なります。

上記の「デリゲート」の概念も、デリゲートを1つと見なすことができる戦略パターンに似ています。同様に、Visitorも一種のコールバックです。 (訪問者は、訪問した各アイテムを処理するための戦略でもあります。)

「コールバック」も「デリゲート」も正式な用語ではなく、あなたの中で有効な以前の定義を参照せずにそれらを議論することはほとんど意味がないため、これはすべて私にとって直感的で他の誰にも理解できない定義を使用しています環境。したがって、私の知る限り、信頼できるものがないので、定義が何であるかを尋ねることはほとんど意味がありません。つまり、この質問に対する他の回答がまったく異なることを言っている可能性が高いという事実。

私の推奨は、セマンティクスの細かな点ではなく、設計のメリット(必要なものを達成するか、密結合を導入しないかなど)に焦点を当てることです。 2つのデザインパターンが類似しているように見える場合、それらを使用して、類似した目標を同等に達成できる可能性があります。

5
millimoose

実現したいのは、サービスがクライアントに依存することを避けながら、元の呼び出し元とサービスの間の双方向通信です。その目標に使用するパターンは、多くの場合、言語の制限によって異なります。関数ポインタ、クロージャ、またはこれらがない場合はコールバックオブジェクト(クロージャと見なされることもあります)を使用します。

そして、同じまたは非常に類似したパターンには、多くの場合、異なる名前があります。

1
nansen