Callback vs Interface

Un article de Le wiki de 2 noisettes - noisette.ch.


Cet article est en cours de réalisation.


Sommaire

Définition

Premièrement c'est quoi :

Callback

Nom masculin dû à sa traduction française : un appel de retour

Un callback est un bout de code exécutable passé en paramètre à un autre bout de code. Le bout de code pourra alors exécuter le callback au moment souhaité.

Interface

Au sens Java, l'interface est une définition de méthodes que contiendra un objet. L'interface Comparable par exemple définit une méthode compareTo qui, si on manipule un objet qui implément cette interface, pourra être utilisée.

Callback vs Interface

La question est donc : à quoi sert l'interface ou le callback ?

L'intérêt d'une interface ou d'un callback est similaire, c'est de pouvoir séparer les acteurs logiques du logiciel, et de pouvoir appeler (donc exécuter) des méthodes plutôt que de "copier - coller" et donc produire de la duplication de code, avec tous les désagrément qu'on lui connait.

Mais pourquoi des callbacks plutot que des simples méthodes ?

L'idée là derrière est de mélanger une multitude de méthodes ou d'objets différents. On définit donc un prototye de méthode, qu'on appellera de la même manière, indépendamment si elle s'applique à un objet A ou B, ou une la méthode A ou B.

L'interface comme le callback nous apporte donc un niveau d'abstraction supplémentaire, qui ne déplaira pas j'en suis sûr.

Donc callback ou interface ?

Les 2 concepts sont grandement similaire, la différence entre eux est que l'interface s'applique dans le cadre d'une programmation orienté objet, alors que les callbacks s'utilisent dans un cadre fonctionnel. A notez que les callbacks peuvent aussi être utilisés dans un cadre OO, mais il faut que le langage de programmation le permette.

En règles générales, c'est donc plutôt le langage de programmation qui tranchera.

Exemple

Si on prend l'exemple d'un pattern connu, celui de l'observateur : sur deux objets, l'un observe, l'autre est observé. Et quand l'objet observé est modifié, l'observateur est informé et se met à jour si nécessaire.

En pseudo-code, avec un interface :

interface Observer { 
  function update(Observed)
}
interface Observed {
  function attach(Observer)
  function detach(Observer)
  function notify()
}
class O1 implements Observer {
  ...
  function update(Observed o) { ... }
  ...
}
class O2 implements Observed {
  ...
  Collection observers;
  ...
  function attach(Observer o) { observers.add(o) }
  function detach(Observer o ) { observers.remove(o) }
  function notify() { 
    foreach (observers as o) o.update(this)
  }
  ...
}

La partie intéressante de l'interface est donc Observer::update qui est appelé dans Observed::notify.

Même exemple, aussi en pseudo-code, avec un callback :

void* obj;
typedef void (*callback1)(void*);
void update_o1(void * obj) { ... } // notre callback

void register_callback(callback1);
void notify_callbacks() {
  foreach (registred_callbacks as cb) (*cb)(obj);
}

register_callback(update_o1);
...
notify_callbacks()

La partie intéressante dans cet extrait est donc (*cb)(obj).

Perfomance

Quelles sont les performances de chacune ?

Dans l'interface, il y a le cout de la recherche de la fonction a appeler en plus

Puisque PHP nous permet de faire les 2 versions, et que c'est un très bon candidat au rapid prototyping, faisons un test avec.

Conclusion