Este video se enfocará En un aspecto avanzado de Pharo,
que son las operaciones reflexivas Necesario para la programación en vivo que usamos.
Analizaremos lo que sucede cuando recompilamos una clase.
Y lo explicaremos las operaciones reflexivas
necesario para implementar programación en vivo
Este es un caso típico.
Por lo general, comenzamos por definir una clase,
luego agregamos métodos y cree instancias para esta clase.
Luego redefinimos la clase y agregar nuevas variables de instancia.
Entonces, ¿qué hacemos con las instancias? eso ya existia
cuando hubo un atributo menos?
Debemos configurar un mecanismo migrar estas instancias
a la nueva versión de la clase.
Luego seguimos trabajando.
Después de eso, veremos las operaciones
que habilite la redefinición dinámica de clases, Recopilación de métodos,
y que permiten
un automático y transparente migración de instancias
a la nueva versión de la clase.
Para hacer esto, necesitamos Recopilar todas las instancias de clase.
Entonces tenemos que cambiar todo lo que usaba estos objetos
y asigna sus indicadores a nuevos objetos
¿Bueno?
Primero, ¿cómo recopilamos? todas las instancias de una clase
Si enviamos el mensaje allInstances a una clase,
muestra todos los objetos que son sus instancias
Es una coleccion de todos los objetos estándar.
Si lo enviamos a la clase de ventana, Obtenemos una colección de objetos de ventana.
Podemos recuperar el primer elemento y envíe un mensaje de "cierre"
ya que el método "cerrado" se define en la clase Ventana.
Otra primitiva reflexiva es punteros a.
Si enviamos este mensaje a un objeto, accedemos a la colección
de todos los objetos que almacena una referencia al objeto
Esto es muy útil
cuando queremos intercambiar objetos.
La primitiva para intercambiar punteros es "convertido".
La idea es habilitarnos para intercambiar dos objetos.
Queremos intercambiarlos simétricamente.
Todo lo que apuntaba a este objeto en el sistema,
en este caso tenemos dos punteros,
Se invertirá para que los elementos ahora apunta a este objeto.
Rompemos los enlaces para las indicaciones que estaban de este lado,
por lo que cambian de objeto.
"Convertirse" significa invertir todos los indicadores. en el sistema simétricamente.
Aquí hay un ejemplo.
Yo creo un punto 1,
que apunta al objeto del punto 0 @ 0 y una variable pt2,
que también apunta al objeto 0 @ 0.
Además de una variable pt3 eso apunta al punto 100 @ 100.
Entonces escribo el primitivo pt1 convertido en:pt3.
Todo lo que apuntaba al objeto denotado por la variable pt1
ahora apuntará al punto 3.
Es decir, todos los punteros a pt1.
Vemos que la variable pt2 señaló al mismo objeto que pt1,
y ahora apunta a lo que fue referenciado por pt3.
En cuanto a pt3, ya que es simétrico, señalará a lo que apuntó pt1.
Arriba arriba
Y pt1 apunta a lo que apuntó pt3.
Los punteros han sido intercambiados simétricamente
La variante asimétrica es convertido hacia adelante
Esto indica que queremos intercambiar punteros.
Todo lo que apuntaba a este objeto se pasará a ese objeto.
Pero no al contrario. Los punteros a este objeto permanecen iguales.
Aquí hay otro ejemplo que usa puntos.
Cuando ejecutamos un convertido hacia adelante,
vemos que impacta en pt1 y pt2.
Pt3 no se vio afectado por el convertido hacia adelante,
y los que señalaron a este objeto no se modifican.
Otra primitiva reflexiva es adoptarInstancia.
Esto cambia la clase de un objeto.
Le pedimos a una clase que adopte una nueva instancia, pasado como un parámetro
Cambiar una clase es muy poderoso, pero algo limitada, herramienta.
Es esencial que la clase original del objeto
en este caso, una instancia,
es compatible con el formato de la clase objetivo.
No puedes simplemente intercambiar cualquier objeto.
A veces está indexado, etcétera.
El formato de un objeto es muy importante.
Miremos a que clase es en esencia.
Una clase es esencialmente un formato.
Un formato especifica el número de variables de instancia
y el tipo de variables, como explicamos en un curso anterior.
Tiene una superclase y un diccionario de métodos.
Aquí tenemos la clase Comportamiento, que es una superclase
de clase de clase, que define el comportamiento básico de la clase.
Es el mínimo básico para una clase.
Entonces, una clase tiene una superclase, un diccionario de método,
y especificaciones de formato.
Ahora resumiré todas las características de comportamiento reflexivo
que hemos discutido hasta ahora,
que dan ciertas instancias comportamiento que es específico de ellos.
Explicaré el código a medida que avancemos.
Vamos a crear una instancia de la clase de comportamiento en estas tres líneas.
Recuerda, es una clase.
Creo una instancia de la clase, que yo llamo Comportamiento.
Eso me da un objeto llamado Comportamiento.
Indico que este objeto hereda de la clase Modelo.
Me gusta esto.
Configuré el formato de este objeto Comportamiento.
Entonces creo una instancia de la clase de modelo aquí.
Es un objeto llamado modelo.
Aquí está la línea importante en este código.
Cambiaré la clase de este objeto modelo
para convertirse en una clase del objeto pasado como un parámetro, llamado Comportamiento.
Rompo el enlace y hazlo una instancia de esta clase.
Esta es una subclase de la clase Modelo.
Ahora puedo compilar Un nuevo método en esta clase.
Compilo con el método foo, que devuelve 2
Estoy haciendo esto en el objeto Comportamiento.
Como podemos ver aquí,
si envío el mensaje foo al objeto Modelo por aquí,
Me gusta esto,
regresará 2
Esto sigue el método de búsqueda.
Envío el mensaje foo.
El modelo de objeto busca el método en su clase, el objeto Comportamiento,
y encuentra con éxito el método.
Funciona a la perfección
Pero si creo una nueva instancia de clase modelo,
Me gusta esto,
y le envío el mensaje foo,
se indica un error por MessageNotUnderstood.
Porque si aplico ToLookUp,
Miro en la clase del objeto, Clase de modelo
pero no encuentro el método foo en su diccionario o superclases.
Este mecanismo avanzado nos permite dotar a una instancia específica
de la clase Model con un comportamiento.
Aplicemos esto a la clase Establecer para aclararlo
Creo set1, una instancia de la clase Set.
El diccionario de método de clase Establecer contiene el método add :.
Para una instancia específica de la clase Set, Quiero cambiar el método add :,
que tiene un comportamiento específico para un conjunto específico.
Entonces, creo una clase "anónima" aquí.
Es una clase específica que hereda. de la clase Establecer.
Aquí está su herencia.
El objeto set2 es una instancia de esta clase "anónima".
En su diccionario de métodos, Redefiniré el método add:
dándole un comportamiento particular.
Ahora, si envío el mensaje agrega: al objeto set2,
este método será seleccionado,
y tendrá un específico, diferente comportamiento
desde el método add:aquí si hubiéramos enviado el mensaje a este conjunto.
Entonces, tenemos dos conjuntos que reaccionan De manera diferente al mensaje add :.
Aquí está el código para llevar a cabo este ejercicio
Al igual que antes, creo una clase
como una instancia de la clase de comportamiento.
Puse la superclase en la clase Establecer.
Configuré el formato.
Compilo el método add: en esta clase anónima.
Estoy redefiniendo el método add: que se define en la clase Establecer.
Uso "Transcript show" para mostrar la ejecución del método agrega :.
Entonces llamo "super" para ejecutar el método agregar:en la clase Establecer.
Ahora probaremos este código. creando un primer set.
Aquí tengo la clase Establecer.
Creo la primera instancia de esta clase, llamado Set.
Le envío el mensaje add :.
Envío add:1, que usa el método agregar:de la clase Establecer.
Si pido la clase Establecer aquí, Voy a tener set.
Pero ahora ejecutaré este primitivo tu ves aqui
Le pido al objeto Establecer que cambie las clases.
y para usar la clase de comportamiento de antes, que es una subclase
de la clase Set.
Entonces, cambia y se vuelve una instancia de la clase Establecer,
que tiene una nueva versión del método agregar :.
Ahora, si envío el mensaje agregar:2 a este objeto,
seleccionará el método add: desde el objeto Comportamiento,
y ejecutará este código.
Podemos verificar en la transcripción
si el método se ha ejecutado.
Eventualmente se ejecutará,
ya que también usamos "super" para el método add:de la clase Set.
Esto nos permite espiar en instancias seleccionadas en Set,
usando esta línea aquí.
Para concluir,
todas estas operaciones reflexivas nos permiten crear herramientas muy innovadoras.
Podemos probar e implementar nuevas funciones
gracias a estas primitivas reflexivas, que promueven la extensibilidad del lenguaje.
Pero hay una regla de oro cuando se usa la reflexion
No debe usarlo de manera inapropiada. en el código de dominio.
Limitamos el uso de códigos reflectantes en el código de dominio.
La reflexión puede violar La encapsulación de los objetos.
Realmente puede ...
Puede sobrepasar reglas de programación de objetos,
y por lo tanto está reservado para la construcción de herramientas.