Bonjour. Alors dans cette séquence, on va voir quelque
chose d'extrêmement intéressant et important en Pharo,
qui est le does not understand. Donc en fait j'imagine
que vous avez déjà eu des débuggers qui sont ouverts avec
la méthode does not understand affichée.
Donc on va voir d'où elle vient et à quoi elle sert.
Donc on va prendre un exemple, ici.
Donc je vais vous l'expliquer.
On a un objet ici, node1.
Cet objet on va lui envoyer le message Coucou Steph.
Donc ici, c'est le symbole Steph.
Donc node1, si vous reprenez le look up, on va remonter à
la classe de cet objet.
Est-ce qu'il existe une méthode coucou sur cette classe?
Non. Alors on va remonter à la super classe.
Est-ce qu'il existe une méthode coucou dans la face object?
Non. Alors que va faire la machine virtuelle?
Elle va dire: je n'ai pas trouvé de méthode
correspondant à l'envoi de messages effectués sur l'objet
donc je fais réifier le message.
Donc réifier, j'en ai déjà parlé dans la séquence sur l'introspection,
sur la réflexion. Donc l'idée de réifier, c'est de
représenter sous la forme d'un objet, un concept qui
normalement est implicite, donc en l'occurrence ici le message.
Donc ici, on va créer un objet pour représenter le message Coucou Steph.
Donc c'est une instance de la classe message en Pharo.
Et puis la machine virtuelle, ce qu'elle va faire, c'est
qu'elle va réenvoyer, elle va refaire un envoi de message
à cet objet node1 ici, sauf qu'elle va lui envoyer le
message does not understand, et lui passer cet objet message en paramètre.
Donc il y a une nouvelle exécution de l'algorithme de look up.
Cette fois, la machine virtuelle va chercher est-ce qu'il
existe la méthode does not understand dans la classe node?
Non. Alors elle remonte.
Donc on remonte dans la super classe.
Est-ce qu'il existe une méthode does not understand dans la classe objet?
Oui, elle est là. Donc là, elle est sous forme abrégée
dnu, mais c'est la méthode does not understand, donc elle
va pouvoir être exécutée.
Donc ce qu'il faut bien comprendre, c'est que does not
understand c'est un message qu'on va envoyer aux objets,
que la machine virtuelle va envoyer aux objets pour vous,
quand un envoi de message a échoué.
Donc toutes les classes peuvent redéfinir cette méthode
does not understand, pour vraiment avoir son propre
comportement quand un message n'est pas compris par l'une de ces instances.
Donc c'est vraiment important, ça permet de construire
énormément de choses grâce à cette méthode does not
understand, grâce à ce (Phon). Donc ça permet de
construire de la délégation automatique, c'est utilisé
aussi dans la programmation distribuée et cetera.
Donc nous, on va voir quelques usages possibles du does
not understand dans cette séquence.
Donc l'idée, par exemple, imaginons que je veuille
rediriger tous les messages reçus par un objet vers un autre.
Donc la délégation simple.
Donc pour ça, je vais construire un objet delegating,
donc qui va stocker la cible, vers quel objet je dois
renvoyer tous les messages. Je vais redéfinir la méthode
does not understand. Je vous l'ai dit, en paramètres elle
prend un objet message qui va contenir le sélecteur du
message qui n'avait pas été compris, ainsi que la liste des arguments.
Et puis je peux demander à ce message de se rediriger, d'être
réenvoyé, donc je vais utiliser send to save target, qui
est bien la variable d'instance.
Donc je vais réenvoyer ce message à un autre objet.
Donc attention, cette pratique c'est extrêmement
puissant, mais également ça nuit un petit peu à la
lisibilité du code.
Vous l'avez ici. Il faut vraiment aller lire le code pour
savoir qui est-ce qui va recevoir le message in fine.
Par contre, c'est extrêmement pratique pour la
construction d'outils ou la construction de mécanismes un
peu avancés, comme je vous l'ai dit précédemment.
Donc on va voir un autre exemple ensemble, le login proxy.
L'idée de base c'est de créer un objet minimal qui va
contenir très peu de méthode, de customiser, de redéfinir
sa méthode does not understand.
Et puis ensuite, ce qu'on va faire, c'est qu'on va
échanger un objet métier grâce à become avec cet objet minimal, ce proxy.
Donc voilà comment on va faire, je crée un objet proxy.
Donc cet objet proxy, je vais mettre un sujet.
Donc le sujet, c'est l'objet que je vais remplacer, donc
la cible, la target.
Et puis je vais, par exemple, mettre un compteur d'invocation.
Donc à chaque fois qu'un message va être reçu, on va
incrémenter le compteur. Dans initialize, je vais mettre à 0.
Le compteur d'invocation, pour l'instant, n'a reçu aucun
message et puis le sujet qui est-ce qu'on va remplacer.
Maintenant on va redéfinir la méthode does not understand
sur ce proxy, donc on va dire à chaque fois qu'il reçoit
un message qu'il ne comprend pas il va afficher sur le
transcript qu'il a reçu un message.
Il va incrémenter son compteur, j'ai reçu un nouveau
message, un de plus et puis je vais transférer le message
à mon sujet. Donc comme précédemment, je transfère le
message a quelqu'un d'autre.
Donc pour le send to, si vous regardez l'implémentation
dans la classe message c'est tout bête, on avait déjà vu,
c'est la méthode perform with arguments.
On en avait déjà parlé dans une séquence précédente, donc
là il n'y a rien de nouveau.
Voyons maintenant un exemple, comment est-ce qu'on peut
utiliser ce login proxy.
Donc on va créer une instance, un objet point, et puis je
vais utiliser maintenant become pour dire: tous ceux qui
pointent sur ce point, ils vont pointer sans s'en rendre
compte sur un login proxy, que j'ai instancié.
Et maintenant, si j'envoie des messages à l'objet point,
donc attention on (Phon) maintenant l'objet point vu qu'il
y a eu become, c'est devenu l'instance du login proxy.
Donc à chaque fois que je lui envoie un message,
forcément ça va s'afficher sur le transcript.
Et puis le compteur d'invocations va être incrémenté.
Vous vous souvenez, dans le does not understand c'est ce qu'on faisait.
Donc on peut voir qu'à la fin, le compteur invocations, il vaut 4 bien 3.
Donc il y a quelques limites, par exemple dans le petit
framework de proxy, exemple que je viens de présenter, il
y a des limites, on ne peut pas forcément capturer par
exemple les messages qu'un objet s'envoie à lui-même, ça va être difficile.
On ne peut pas utiliser un become sur des classes, donc
les opérations réflexives ont des limites en Pharo.
Par exemple, ce qui va être compliqué aussi, imaginons
que l'objet à remplacer et le proxy comprennent tous les 2 le même message.
Ce qui fait que quand je vais envoyer le message au
proxy, il va répondre à la place de le capturer avec un
does not understand, et de le transférer à son objet cible.
Donc, il y a d'autres frameworks de proxy, plus puissants
qui existent en Pharo, qui permettent de vraiment tout
capturer, mais ils sont plus importants qu'un exemple
aussi petit que celui-là.
Donc une autre application, un autre exemple d'utilisation
de cette technique, ça peut être par exemple la
génération des accesseurs ou même des méthodes
dynamiquement. Par exemple, imaginons ici toujours
définie la méthode does not understand et puis je vais
dire: OK, il y a un message qui a été reçu donc je vais
tester est-ce que j'ai des variables d'instances qui incluent ce message?
Si oui, alors je vais générer une nouvelle méthode donc
je vais utiliser (Phon) pour générer une nouvelle méthode
sur la classe, qui va répondre directement
la valeur de cette variable.
Donc je suis en train de générer l'accesseur en lecture d'une variable.
Et puis si vraiment si le message qui a été envoyé ne
correspond pas à un nom d'une variable d'instances, je
fais un super does not understand.
Donc ça va nous permettre d'automatiquement remplir les
accesseurs en lecture, en fonction du fait qu'ils ont été
appelés ou pas sur un objet.
Donc en conclusion dans cette séquence, on peut voir qu'on
va être capables d'utiliser des objets minimaux.
Donc on a vu que ce n'était pas des objets qui étaient
directement instance de la classe object mais de la
classe proto object, donc c'est vraiment des tout petits objets.
Ça peut être la base pour des frameworks de proxy.
Grâce à la redéfinition de la méthode does not
understand, on va être capable de capturer le fait qu'il
y a un envoi de message qui a raté, et on va pouvoir
avoir un comportement, rediriger ce message ailleurs et
avoir un traitement spécifique.
Donc c'est un (Phon) qui est extrêmement puissant, qui
est à la base de beaucoup d'outils en Pharo.
Et par contre, il faut faire attention, il faut vraiment
l'utiliser que quand c'est réellement nécessaire, quand
vraiment on en a un besoin. Donc ne mettez pas ça dans du
code métier, encore ça reste une technique avancée de Pharo.