Hola, este video explicará una característica importante de Pharo,
el gancho doNotUnderstand.
Seguramente ya habrás visto una ventana de Debugger con este mensaje.
¿De dónde viene y, para qué sirve?
Veamos un ejemplo.
Tenemos el objeto node1.
Enviaremos a este objeto el mensaje coucou: stef.
Desde el nodo1, seguimos el método de búsqueda
hasta la clase del objeto.
No encontramos el método coucou en esta clase.
Entonces, vamos a la superclase, pero tampoco está allí.
El sistema virtual nos informa
que no puede encontrar un método coincidente, por lo que reifica el mensaje.
Discutimos sobre la reificación en el video de introspección y reflexión.
Reificar significa representar un concepto implícito como un objeto.
Aquí, es un mensaje.
Creamos un objeto para representar el mensaje
Es una instancia de la clase Message.
El sistema virtual reenviará un mensaje
al objeto node1.
Envía el mensaje doesNotUnderstand, pasando el objeto como un parámetro.
Esta es una nueva ejecución. del algoritmo de búsqueda.
El sistema no encontrará el método doesNotUnderstand en la clase Node.
Entonces regresa para buscar en la superclase.
Encuentra el método, abreviado a DNU.
Ahora puede ejecutar el método.
DoesNotUnstandstand es un mensaje
que la maquina virtual envía a los objetos
cuando un mensaje ha fallado.
Todas las clases pueden redefinir este método
para darle un comportamiento específico cuando no se comprende un mensaje.
Este método es una herramienta importante
que nos permite construir muchas características.
Se usa en la delegación automática,
programación distribuida, y así sucesivamente.
Aquí veremos algunos usos de doesNotUnderstand.
Supongamos que queremos redirigir todos nuestros mensajes a un objeto diferente.
En una delegación simple, creo un objeto que almacena el objetivo,
donde se enviarán los mensajes.
Redefino el método doesNotUnderstand.
Toma el objeto aMessage como parámetro,
que contiene el selector del mensaje fallido.
Entonces puedo preguntarle a este mensaje que se reenvie.
Uso "sendTo: self target", que es la variable de instancia.
Reenvío el mensaje a otro objeto.
Ten cuidado, esta es una función poderosa
que puede interferir con la legibilidad del código.
Como se explica aquí.
El código mostrará quien finalmente recibe el mensaje.
Es muy útil para construir herramientas
y mecanismos avanzados.
Otro ejemplo que veremos es LoggingProxy.
La idea básica aquí
es crear un objeto mínimo que contiene pocos métodos,
y personalizar su doesNotUnderstand:.
Luego intercambiaremos un objeto de dominio
con este proxy, u objeto mínimo, usando "become".
Primero, creamos un objeto proxy.
Le damos un "subject" al objeto proxy,
que es el objeto vamos a reemplazar,
o el objetivo.
Agregamos InvocationCount para incrementar el contador con cada mensaje
Ponemos el contador al inicializar en 0, ya que no ha recibido mensajes.
Luego agregamos el "subjet", que es lo que será reemplazado.
Ahora redefinimos el método DNU en este proxy.
Cada vez que un nuevo mensaje no se entiende,
su recepción aparece en el Transcript, y el contador se incrementa.
Luego reenviamos el mensaje al sujeto objetivo.
Como antes, redirigimos el mensaje a otra parte.
Para sendTo, como ves en la implementación de la clase Message,
simplemente utilizamos el método "perform:withArguments:" .
Ya explicamos esto en un curso anterior.
Veamos un ejemplo.
¿Cómo utilizamos este LoggingProxy?
Vamos a crear una instancia, el objeto punto.
Luego usaremos "become"
para que todo lo que apunte a este punto
inadvertidamente señale a LoggingProxy,
al que instanciamos.
Ahora, si enviamos mensajes al objeto punto,
observando que "become" es una instancia de LoggingProxy,
cada vez que le enviemos un mensaje,
se mostrará en el Transcript
y se incrementará el contador.
Esto es lo que hicimos en doesNotUnderstand.
Al final, el contador muestra un valor de 3.
Hay limites a esta variante de proxy,
como se ve en el último ejemplo.
Por ejemplo, no podemos capturar mensajes que un objeto envía a sí mismo.
Eso se vuelve complicado.
No podemos usar "become" con clases, ya que los modelos reflexivos tienen limitaciones.
También es arriesgado cuando el proxy y el objeto a reemplazar
ambos entienden el mismo mensaje.
Cuando envío el mensaje al proxy,
responderá, en lugar de capturarlo con DNU
y transferirlo al objeto de destino.
Pharo tiene otras variantes de proxys más poderosas que atrapan todo,
pero son más complejos que este simple ejemplo.
Otro ejemplo de cómo aplicar esta técnica
es generar dinámicamente accesors, o incluso métodos.
Aquí he redefinido el método doesNotUnderstand.
Veo que se ha recibido un mensaje,
entonces pruebo si tengo en la instancia variables que incluyen el mensaje.
Si es así, genero un nuevo método usando "compile"
para definir un nuevo método para la clase.
Esto devolverá el valor de la variable.
Aquí estoy generando el read-accessor de la variable.
Si el mensaje enviado no coincide con el nombre
de una variable de instancia, envío super doesNotUnderstand.
Esto nos permite crear read-accessors automáticamente,
dependiendo de si han sido llamados o no.
En conclusión,
Hemos visto cómo usar objetos mínimos.
No son instancias directas de la clase Object,
pero de la clase ProtoObject.
Pueden ser la base de proxies.
Al redefinir el método doesNotUnderstand, podemos capturar
la existencia de un mensaje fallido y luego redirigirlo.
Es un gancho poderoso que proporciona la base de muchas herramientas en Pharo.
Pero debes ser muy cuidadoso cuando lo usas.
Solo se debe usar cuando sea necesario.
No lo uses en el código de dominio todavía, es una técnica muy avanzada.