ホームページ  >  記事  >  Java  >  Javaのコールバック機構の詳しい説明

Javaのコールバック機構の詳しい説明

高洛峰
高洛峰オリジナル
2017-01-24 11:52:351333ブラウズ

メソッド呼び出しの観点から、モジュール間には常に特定のインターフェイスが存在し、同期呼び出し、コールバック、非同期呼び出しの 3 つのカテゴリに分類できます。以下では、コールバック メカニズムの詳細に焦点を当てます。

1. 概要

Java のコールバック メカニズムは比較的一般的なメカニズムですが、一部の大規模なフレームワークでは、コールバック メカニズムがあらゆる場所で使用されることがあります。この記事では、いくつかの具体的な例を通じて、Java のコールバック メカニズムにゆっくりとアプローチしていきます。

2. コールバック

いわゆるコールバック: クラス A がクラス B のメソッド C を呼び出し、次にクラス B がクラス A のメソッド D を呼び出します。このメソッド D はコールバック メソッドと呼ばれます。実際の使用では、次のようなさまざまなコールバック形式が存在します。

2.1 同期コールバック

ここではそのような状況を想定します。

A社の部長Bは部下(プロジェクトマネージャーC)にアンケートをするように言いましたが、Cは自分でやる必要はありませんでした。マネージャー C に、その下のプログラマー D にそれを完了させるよう手配してもらうことができます。マネージャー C はプログラマー D を見つけて、これから研究タスクを完了する必要があると言いました。そして、調査結果をマネージャーCに伝えます。問題がある場合でも、続行する必要があります。 なぜなら、ここでは C が D に何かをするように依頼し、その後 D はその結果を C に伝えなければならないからです。これがコールバックモデルです。以下は、一般的なコールバックのクラス図です。

Javaのコールバック機構の詳しい説明

まず、コールバック インターフェイス CallbackInterface が必要です。

CallbackInterface.java

public interface CallbackInterface {
  public boolean check(int result);
}


バックグラウンドで、プログラマ D は結果を通信したいと考えています。プロジェクト マネージャー C と通信するには、プロジェクト マネージャーは上記のコールバック インターフェイスを実装する必要があります:

Manager.java

public class Manager implements CallbackInterface {
 
  private Programmer programmer = null;
 
  public Manager(Programmer _programmer) {
    this.programmer = _programmer;
  }
 
  /**
   * 用于 Boss 下达的委托
   */
  public void entrust() {
    arrange();
  }
 
  // 进行安排下属进行 study 工作
  private void arrange() {
    System.out.println("Manager 正在为 Programmer 安排工作");
    programmer.study(Manager.this);
    System.out.println("为 Programmer 安排工作已经完成,Manager 做其他的事情去了。");
  }
 
  @Override
  public boolean check(int result) {
    if (result == 5) {
      return true;
    }
    return false;
  }
 
}


プログラマー D の場合、通信するためにマネージャー C への参照を保持する必要があります。彼と一緒に。ただし、これは部長Bが部長Cに手配を依頼した仕事です。つまり、マネージャー B1、B2 など、他のマネージャーもここで許可されます。マネージャがコールバック インターフェイスを実装しているため、プログラマ D はこのインターフェイスを直接保持できます。以下のように:

Programmer.java

public class Programmer {
 
  public void study(CallbackInterface callback) {
    int result = 0;
    do {
      result++;
      System.out.println("第 " + result + " 次研究的结果");
    } while (!callback.check(result));
 
    System.out.println("调研任务结束");
  }
}

これはクライアントテストと同等であるため、ディレクターにとってはより単純かつ明確です:

Boss.java

public class Boss {
 
  public static void main(String[] args) {
    Manager manager = new Manager(new Programmer());
    manager.entrust();
  }
}

実行結果:

Managerプログラマの仕事の手配
1回目の検討の結果
2回目の検討の結果
3回目の検討の結果
4回目の検討の結果
5回目の検討の結果
調査タスク終了
プログラマの仕事の手配が完了, マネージャーは他のことをしに行きました。

2.2 非同期コールバック

上記の例でも、プロジェクト マネージャーは常に調査結果を待っているわけではありません。しかし、この仕事をあなたに与えた後は、彼はそれを気にしません。彼は自分のことをし、あなたは自分のことをするでしょう。したがって、コールバック関数は非同期で処理する必要があります。
そこで、ここでは Programmer クラスのコードを次のように変更する必要があります:

Programmer.java

public class Programmer {
 
  public Programmer() {
  }
 
  public void study(CallbackInterface callback) {
    new StudyThread(callback).start();
  }
 
  // --------------------------- Programmer 正在做的工作 ---------------------------
 
  class StudyThread extends Thread {
 
    CallbackInterface callback = null;
 
    public StudyThread(CallbackInterface _callback) {
      callback = _callback;
    }
 
    @Override
    public void run() {
      int result = 0;
      do {
        result++;
        System.out.println("第 " + result + " 次研究的结果");
      } while (!callback.check(result));
 
      System.out.println("调研任务结束");
    }
  }
}

実行結果:

マネージャーはプログラマーの仕事を手配しています
プログラマーの仕事の手配は完了しました、マネージャーは他のことをやっていて、物事は進みました。
最初のスタディの結果
2回目のスタディの結果
3回目のスタディの結果
4回目のスタディの結果
5回目のスタディの結果
リサーチタスクの終了

2.3 クロージャとコールバック

クロージング クロージャは呼び出し可能です作成されたスコープからの情報を記録するオブジェクト。

2.3.1 通常の通話

まず、通常の状況で通話がどのように実行されるかを確認します。
Incrementable.java

interface Incrementable {
  void increment();
}

これは通常のインターフェイスです (通常の呼び出しでは、単なる通常のインターフェイスであり、コールバックでは、コールバック インターフェイスです。これは理解しやすいはずです)。

Callee1.java

class Callee1 implements Incrementable {
 
  private int i = 0;
 
  @Override
  public void increment() {
    i++;
    System.out.println(i);
  }
 
}

Callbacks.java

public class Callbacks {
  public static void main(String[] args) {
    Callee1 callee1 = new Callee1();
    callee1.increment();
  }
}

Callbacks はテスト クライアント クラスです。言うことはありません。上のコードを見てください。

2.3.2 コールバックの予備テスト

上記の通常の呼び出しについては何も言うことはありません。通常の Java プログラマーにとって、これは何も考えずに実行できるはずです。

さて、コールバックを形成したい場合、プログラムの構造や論理的思考に基づいて、呼び出し先を 1 つだけ (コールバック オブジェクト Callee1) にすることは不可能であり、呼び出し元オブジェクトも必要です。呼び出し元は次のように記述できます:

Caller.java

class Caller {
 
  private Incrementable callbackReference;
 
  public Caller(Incrementable _callbackReference) {
    callbackReference = _callbackReference;
  }
 
  void go() {
    callbackReference.increment();
  }
}

ここで Caller はコールバック インターフェイス callbackReference への参照を保持します。これは、前述のプログラマーがプロジェクト マネージャーへの参照を保持する必要があるのと同じです。このリファレンスを通じてプロジェクト マネージャーと通信できます。ここの callbackReference もこの役割を果たします。

それでは、テスト クラスの作成を見てみましょう:

Callbacks.java

public class Callbacks {
  public static void main(String[] args) {
    Callee1 callee1 = new Callee1();   
    Caller caller1 = new Caller(callee1);
    caller1.go();
  }
}

对于到目前为止的程序代码,完全可以对比上面项目经理安排程序员调研技术难题的代码。有异曲同工之妙。

2.3.3 闭包回调

相比于正常的回调,闭包回调的核心自然是在于闭包,也就是对作用域的控制。 
现在假设有一个用户(其他程序员)自定义了一个 MyInCrement 类,同时包含了一个 increment 的方法。如下:

class MyInCrement {
 
  public void increment() {
    System.out.println("MyCrement.increment");
  }
 
  static void f(MyInCrement increment) {
    increment.increment();
  }
}

另外有一个类 Callee2 继承自上面这个类:

class Callee2 extends MyInCrement {
 
  private int i = 0;
 
  public void increment() {
    super.increment();
    i++;
    System.out.println(i);
  }
}

显而易见这里如果要调用 increment() 方法,就变成了一般的函数调用了。所以这里我们需要修改上面的 Callee2 类,修改的目标就是让 Callee2 类可以兼容 MyInCrement 类的 increment() 方法和 Incrementable 的 increment() 方法。修改后:

class Callee2 extends MyInCrement {
 
  private int i = 0;
 
  public void increment() {
    super.increment();
    i++;
    System.out.println(i);
  }
 
  private class Closure implements Incrementable {
 
    @Override
    public void increment() {
      Callee2.this.increment();
    }
  }
 
  Incrementable getCallbackReference() {
    return new Closure();
  }
}

注意,这里的 Closure 类是一个私有的类,这是一个闭包的要素。因为 Closure 类是私有的,那么就要有一个对外开放的接口,用来对 Closure 对象的操作,这里就是上面的 getCallbackReference() 方法。 Caller 类则没有改变。 
对于测试客户端就直接看代码吧:

public class Callbacks {
  public static void main(String[] args) {   
    Callee2 callee2 = new Callee2();
    Caller caller2 = new Caller(callee2.getCallbackReference());
    caller2.go();
  }
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持PHP中文网。

更多Javaのコールバック機構の詳しい説明相关文章请关注PHP中文网!

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。