Commits

Miguel Gordian committed 7cf3392

Clases anónimas y miembro

Se incluye el tema de clases anónimas y miembro siendo así la quinta entrega del
tour.

Se agrega la imagen ubicada como source/_static/trompon.png la cual se incluye en
la portada del pdf generado por Sphinx.

  • Participants
  • Parent commits b462442

Comments (0)

Files changed (3)

source/_static/trompon.png

Added
New image

source/anonimos_clasesMiembro.rst

+=========================
+Clases anónimas y miembro
+=========================
+
+Esta es la cuarta parada en el tour de Ceylon. En la parada anterior hemos
+aprendido acerca de herencia y refinamientos. Es momento de completar
+nuestra introducción a la programación orientada a objetos en Ceylon 
+aprendiendo acerca de las clases anónimas y clases miembro.
+
+---------------
+Clases anónimas
+---------------
+
+Si una clase no tiene parámetros, es posible usar una declaración corta
+que defina una instancia con nombre de la clase, sin proveer un nombre
+para la clase misma. Esto es usualmente de mas ayuda cuando estamos 
+extendiendo una clases abstracta o implementando una interfaz.
+
+.. code-block:: ceylon
+    
+    doc "El origen"
+    object origen extends Polar(0.0, 0.0) {
+        descripcion => "origen";
+    }
+
+Una clase anónima puede extender una clase ordinaria y satisfacer una
+interfaz.
+
+.. code-block:: ceylon
+    
+    shared object consoleWriter satisfies Writer {
+        formatter = StringFormatter();
+        write(String string) => process.write(string);
+    }
+
+La desventaja de la declaración de un objeto es que no podemos escribir
+código que refiera a el tipo concreto de `origen` o `consoleWriter`, 
+únicamente a la instancia con nombre.
+
+Tal vez estés tentado a pensar a la declaración de objetos como definición
+de `singletons`, pero eso no es del todo correcto.
+
+- La declaración de un objeto en `toplevel`, de hecho define un `singleton`.
+- La declaración de un objeto anidado en una clase define un objeto por cada
+  instancia de la clase contenedora.
+- La declaración anidada en un método, getter, o setter da como resultado un
+  nuevo objeto cada vez que el método, getter o setter es ejecutado.
+
+Veamos como esto puede ser útil:
+
+.. code-block:: ceylon
+    
+    interface Subscription {
+        shared formal void cancel();
+    }
+
+    Subscription register(Suscriber s) {
+        subscribers.append(s);
+        object subscription satisfies Subscription {
+            shared actual void cancel() => 
+                subscribers.remove(s);
+        }
+        return subscription;
+    }
+
+Note como este código de ejemplo hace hábilmente uso de el hecho que la
+declaración anidada recibe una closure de los valores contenidos en la 
+declaración del método contenedor.
+
+Una manera distinta de entender  acerca de la diferencia de un objeto y
+una clase es pensar que una clase es como un `object` con parámetros.
+(Por supuesto hay una gran diferencia: una declaración  de una clase
+define un tipo con nombre y con esto podemos referirnos a el en otras
+partes del programa.) Como veremos después, Ceylon nos permite pensar
+en los métodos como atributos con parámetros.
+
+Un declaración `object` puede refinar un atributo declarado con `formal`
+o `default` mientras este sea un suptipo del tipo declarado en el atributo
+a refinar.
+
+.. code-block:: ceylon
+    
+    shared abstract class App() {
+        shared formal OutputStream stream;
+        ...
+    }
+
+
+    class ConsoleApp() extends App() {
+        shared actual object stream
+            satisfies OutputStream { ... }
+        ...
+    }
+
+Sin embargo, un `object` no podra ser mismo declarado
+`formal` o `default`.
+
+
+--------------------------------
+Clases miembro y su refinamiento
+--------------------------------
+
+Probablemente has usado anidar una clase dentro de un método o clase. Desde
+que Ceylon es un lenguaje con bloques de estructura recursivos, la idea de 
+una clase anidada es mas que natural. Pero en Ceylon, una clase anidada no
+abstracta es un miembro del tipo contenedor. Por ejemplo, `BufferReader`
+define la clase miembro `Buffer`:
+
+.. code-block:: ceylon
+    
+    class BufferReader(Reader reader)
+            satifies Reader {
+    
+        shared default class Buffer() 
+            satisfies List<Character> { ... }
+
+        ...
+
+    }
+
+La clase miembro `buffer` es anotada con `shared`, entonces podemos instanciar 
+la clase de la siguiente manera:
+
+.. code-block:: ceylon
+    
+    BufferReader br = BufferReader(ExampleReader());
+    BufferReader.buffer b = br.Buffer();
+
+Note que el tipo anidada deberá ser identificado junto con el tipo contenedor
+cuando es usada fuera de la clase.
+
+El miembro de la clase `Buffer` es también anotado con`default`, así que 
+podemos refinarlo en un subtipo de `BufferReader`:
+
+.. code-block:: ceylon
+    
+    class BufferFileReader(File file) 
+            extends BufferReader(FileReader(file)) {
+        shared actual class Buffer() 
+                extends super.Buffer() { ... }
+        ...
+    }
+
+Es correcto: ¡Ceylon nos permite "sobreescribir" una clase miembro de un
+supertipo!
+
+Note que `BufferFileReader.Buffer` es una subclase de `BufferReader.Buffer`.
+
+Ahora, la instancia anterior `br.buffer()`, !es una operación polimorfa¡
+Puede devolver una instancia de `BufferReader.Buffer` o de 
+`BufferReader.buffer`, dependiendo al que refiera `br` de `BufferReader`
+o `BufferFileReader`. Esto es mas que un lindo truco. La instanciación
+nos permite eliminar al concepto llamado "factory method pattern" de 
+nuestro código.
+
+Es posible incluso, definir una clase miembro `formal`. Una clase miembro
+`formal` puede declarar miembros `formal`.
+
+.. code-block:: ceylon
+
+    abstract class BufferReader (Reader reader)
+            satisfies Reader {
+        shared formal lass Buffer() {
+            shared formal Byte read();
+        }
+        ...
+    }
+    
+En este caso, una subclase concreta de la clase `abstract` deberá refinar
+los miembros `formal` de la clase.
+
+.. code-block:: ceylon
+    
+    shared class BufferFileReader(File file)
+            extends BufferReader(FileReader(file)) {
+        shared actual class Buffer() 
+                extends super.Buffer() {
+            shared actual Byte read() {
+                ...
+            }
+        }
+        ...
+    }
+
+Nótese la diferencia entre una clase `abstract` y una clase miembro `formal`.
+Una clase anidada `abstract` y no necesita ser refinada por subclases 
+concretas de la clase contenedora. Una clase miembro `formal` puede ser 
+instanciada y deberá ser refinada por cada subclase de la clase contenedora.
+
+Es un interesante ejercicio comparar el refinamiento de las clase miembro
+en Ceylon con la funcionalidad de inyección de dependencias en los 
+frameworks con Java. Ambos mecanismos proveen un significado de abstraer
+la operación de instanciación de un tipo. Puedes pensar que las 
+subclases que refinan un miembro tipo como llenando el mismo rol como una
+configuración de dependencia en un framework de inyección de dependencias.
+
+"""""""""""
+Aun hay mas
+"""""""""""
+
+Clases miembro y su refinamiento permiten a Ceylon soportar `type families`.
+No hablaremos de ello en este tour.
+
+En la siguiente estación, conoceremos a las secuencias, basandose Ceylon en el
+tipo "Array".  
     clases
     atributos_estructuras
     herencia_refinamiento_interfaces
+    anonimos_clasesMiembro