Sans les pointeurs de fonction, quelle est la méthode recommandée pour implémenter Callback en Java - autres que les interfaces?

StackOverflow https://stackoverflow.com/questions/626669

  •  06-07-2019
  •  | 
  •  

Question

J'ai quelques classes qui veulent se transmettre des informations et être rappelées ultérieurement, en utilisant ces informations (modèle de rappel).

Dans ma candidature, ce mécanisme a deux objectifs:

  • exécution planifiée / différée
  • exécution asynchrone avec messagerie

Mes objets se disent essentiellement "quand vous avez fini de faire X, rappelez-moi et dites-moi de faire Y avec Z (parce que je l'aurai oublié à ce moment-là)" . Où X pourrait simplement attendre le bon moment, mais aussi communiquer avec un service distant ou appeler une fonction locale.

Maintenant, s’il y avait des pointeurs de fonction (ou l’équivalent) en Java, j’implémenterais des "Job". classe contenant un plus les arguments nécessaires. Par exemple, en PHP, cette structure devrait stocker un nom de classe, un nom de fonction et un tableau d'arguments. En C, ce serait un pointeur sur la fonction et je devrais donner aux arguments le même nombre et le même type pour tous les appels.

En Java, l’approche habituelle consiste à avoir une interface implémentée par toutes les classes qui veulent être rappelées, comme ceci:

public interface ICallable {
    public void call_me(Object data);
}

Maintenant, cela ne fonctionnerait pas pour moi, car

  • les objets à rappeler peuvent utiliser un ensemble de méthodes différent pour prendre l'appel
  • l'appelant n'est pas celui qui décide quel appel doit être passé

Mon problème, c’est peut-être que j’essaie d’avoir une structure de données et une procédure d’appel communes pour les différents rappels, mais en principe, cela me semble logique.

Qu'est-ce qu'un bon modèle de conception pour aborder cette situation en Java?

Était-ce utile?

La solution

Je pense que vous constaterez qu'une interface est la meilleure solution. Je ne comprends pas votre objection à eux. Si le destinataire doit faire appel à une méthode différente, demandez à la méthode Interface d’appeler la méthode différente.

Si votre classe de receveur doit disposer de plusieurs gestionnaires, vous pouvez utiliser des classes internes anonymes implémentant l'interface, une pour chaque type de gestionnaire dont vous avez besoin. Par exemple, si l'expéditeur utilise une interface appelée "ListenerInterface", votre destinataire peut définir une classe interne anonyme qui implémente ListenerInterface et appelle la méthode du destinataire "handlerFunction".

   sender.addListener(new ListenerInterface()
   {
      public void callback(Object arg)
      {
         handlerFunction(arg);
      }
   });

Autres conseils

Vous pourriez utiliser un concept similaire à classes internes anonymes

Une autre référence ici

J'utiliserais une interface, comme vous l'avez décrit, puis une classe anonyme pour vos rappels. Par exemple, depuis l’appelant:

ICallback callback = new ICallback() { 
    public void call_me(Object data) { this.actionToCall(data); }
}
serverObject.doX(callback);

(La syntaxe peut être légèrement différente de celle.)

De cette façon, vous pouvez spécifier dans l’appelant original (au moment de l’appel) quelle action entreprendre une fois terminé.

Si vous ne voulez vraiment pas utiliser d'interfaces (et croyez-moi, vous le faites!), vous pouvez utiliser la réflexion pour obtenir la méthode que vous souhaitez appeler, puis la transmettre à celle qui doit effectuer l'appel. C’est aussi proche d’un pointeur de fonction C que vous allez obtenir.

La réflexion sera plus lente (probablement) que le moyen de l’interface de le faire (mais cela n’aura pas d’importance à moins d’être appelé fréquemment).

Reflection n'aura pas le type à la compilation qui vérifie la manière de procéder de l'interface (ce qui signifie que vous pouvez planter au moment de l'exécution).

La réflexion sera un code plus laid que le moyen de l’interface de le faire aussi.

Mais si vous voulez vraiment vraiment simuler les pointeurs de fonction C, la réflexion est aussi proche que possible.

Les rappels sont une idée générale et vous ne devriez pas essayer une interface unique. Faites votre interface de rappel spécifique à l'utilisation. Il doit correspondre à la sémantique du type auquel il est transmis et le rappel est effectué. L'implémentation habituelle de l'interface de rappel serait faite en tant que classe interne anonyme. Résistez à la tentation d'implémenter l'interface dans une classe externe, ce qui entraînerait un type incohérent.

Je ne comprends peut-être pas le problème, mais il me semble que vous auriez intérêt à mettre en place un système d’événement.

En gros, vous configurez un gestionnaire d'événements et les classes qui souhaitent en savoir plus sur l'événement s'abonnent au gestionnaire d'événements. Donc, pour votre problème, quand X est fait, il déclencherait un FinishedProcessingEvent () auquel votre objet serait abonné. Lorsque votre objet reçoit cet événement (avec tous les autres abonnés qui se soucient de l'événement), il fera l'action appropriée (Y avec Z). Ces actions étant définies dans les objets, différents objets peuvent effectuer différentes tâches en fonction des mêmes événements.

Est-ce que cela vous aide?

Je suis sûr qu’il existe un modèle intéressant qui résout votre problème, mais je choisirais une approche simple en utilisant une infrastructure. Si vous remplissez des demandes et des réponses dans une file de messages, comme JMS, votre système pourrait être plus simple et plus robuste, car vous pourriez gérer des événements prenant quelques secondes ou plusieurs semaines sans vous soucier des redémarrages du système, de la persistance et de l'intégrité des messages.

Je n'y ai pas trop réfléchi, mais Java 5+ Future (ou ses sous-interfaces) peut être utile à cet effet.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top