Maison  >  Article  >  Java  >  Explication détaillée du mécanisme de rappel de Java

Explication détaillée du mécanisme de rappel de Java

高洛峰
高洛峰original
2017-01-24 11:52:351340parcourir

Il existe toujours une certaine interface entre les modules. Du point de vue des méthodes d'appel, ils peuvent être divisés en trois catégories : les appels synchrones, les rappels et les appels asynchrones. Ce qui suit se concentre sur le mécanisme de rappel en détail.

1. Présentation

Le mécanisme de rappel en Java est un mécanisme relativement courant, mais il peut être moins utilisé dans votre programme. on retrouve partout dans le cadre. Cet article abordera lentement le mécanisme de rappel de Java à travers quelques exemples spécifiques.

2. Rappel

Le soi-disant rappel : la classe A appelle une méthode C dans la classe B, puis la classe B appelle à son tour une méthode dans la classe A. D, cette méthode D est appelée méthode de rappel. En utilisation réelle, il existera différents formulaires de rappel, tels que les suivants.

2.1 Rappel synchrone

Ici, j'assume une telle situation.

Le directeur B de l'entreprise A a dit à son subordonné (chef de projet C) de faire une enquête, mais C n'avait pas besoin de le faire lui-même. Vous pouvez demander au responsable C de faire en sorte que le programmeur D en dessous de lui le termine. Le responsable C a trouvé le programmeur D et lui a dit qu'il devait maintenant effectuer une tâche de recherche. Et informez le responsable C des résultats de l’enquête. S'il y a des problèmes, vous devez quand même continuer. Parce qu'ici C demande à D de faire quelque chose, et ensuite D doit encore communiquer le résultat à C. Il s'agit du modèle de rappel. Ce qui suit est un diagramme de classes d'un rappel général :

Explication détaillée du mécanisme de rappel de Java

Nous devons d'abord avoir une interface de rappel CallbackInterface

CallbackInterface.java

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


En arrière-plan, le programmeur D souhaite communiquer les résultats avec le chef de projet C, le chef de projet ici doit donc implémenter l'interface de rappel ci-dessus :

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


Pour le programmeur D, il doit détenir une référence au manager C donc qui communique avec lui. Cependant, il s'agit d'une tâche que le directeur B a demandé au gestionnaire C d'organiser. En d'autres termes, d'autres managers peuvent également être autorisés ici, comme les managers B1, B2, etc. Parce que les managers ont implémenté l'interface de rappel, le programmeur D peut directement gérer cette interface. Comme suit :

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("调研任务结束");
  }
}

C'est plus simple et plus clair pour le réalisateur, car cela équivaut à un test Client :

Boss.java

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

Résultat en cours :

Le responsable organise le travail du programmeur
Résultats de la première étude
Résultats de la 2ème étude
Résultats de la 3ème étude
Résultats de la 4ème étude
Résultats de la 5ème étude
Fin de la tâche de recherche
Organiser le travail du programmeur Il est terminé et le directeur est parti faire autre chose.

2.2 Rappel asynchrone

Toujours avec l'exemple ci-dessus, votre chef de projet ne peut pas toujours attendre les résultats de vos recherches. Mais après vous avoir confié cette tâche, il ne s’en souciera pas. Il fera son travail et vous ferez le vôtre. Par conséquent, la fonction de rappel doit être traitée de manière asynchrone.
Donc, ici, nous devons modifier le code de la classe Programmer comme suit :

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("调研任务结束");
    }
  }
}

Résultats de l'opération :

Le manager organise le travail du programmeur
L'organisation du travail du programmeur est terminée et le manager est parti faire autre chose.
Résultats de la 1ère étude
Résultats de la 2ème étude
Résultats de la 3ème étude
Résultats de la 4ème étude
Résultats de la 5ème étude
Tâches de recherche Fin

2.3 Fermetures et rappels

Une fermeture est un objet appelable qui enregistre certaines informations de la portée dans laquelle il a été créé.

2.3.1 Appels normaux

Tout d'abord, nous pouvons examiner comment les appels sont effectués dans des circonstances normales.
Incrementable.java

interface Incrementable {
  void increment();
}

Il s'agit d'une interface commune (c'est juste une interface commune dans un appel normal, et c'est une interface de rappel dans un rappel. Cela devrait être facile à comprendre).

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 est une classe de client test, il y a pas grand chose à dire, il suffit de regarder le code ci-dessus.

2.3.2 Test préliminaire des rappels

Il n'y a rien à dire sur les appels ordinaires ci-dessus, car pour un programmeur Java normal, cela devrait être quelque chose qui peut être fait sans même y penser .

Maintenant, si vous souhaitez former un rappel, il est impossible d'avoir un seul appelé (l'objet de rappel Callee1) en fonction de la structure du programme ou de la pensée logique. Vous avez également besoin d'un objet appelant. L'appelant peut s'écrire comme suit :

Caller.java

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

Ici, l'appelant détient une interface de rappel Reference callbackReference, comme mentionné ci-dessus, le programmeur doit détenir une référence au chef de projet, afin de pouvoir communiquer avec le chef de projet via cette référence. La callbackReference joue ici également ce rôle.

Jetons maintenant un coup d'œil à l'écriture de la classe de test :

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中文网。

更多Explication détaillée du mécanisme de rappel de Java相关文章请关注PHP中文网!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn