Mostrando entradas con la etiqueta poo. Mostrar todas las entradas
Mostrando entradas con la etiqueta poo. Mostrar todas las entradas

sábado, 1 de agosto de 2015

Clase Selfie en Joose JS

Código

Class("Fotografia", {
    has: {
        alto: {is: "ro"},
        ancho: {is: "rw"},
    },
    methods: {
        clear: function () {
            this.alto = 0;
            this.setAncho(0);
        }
    }
})
Class("Selfie", {
    isa: Fotografia,
    has: {
        etiqueta: {init: "yo"}
    },
    after: {
        clear: function () {
            this.etiqueta = "yo";
        }
    }
})
var foto= new Selfie({ancho: 360, alto:240});
foto.etiqueta= "Ricky Martin";

Explicación


Este es un ejemplo de Joose para crear una clase que hereda de otra. La función Class() toma dos parámetros: el nombre de la clase y la definición de la clase pasada como un objeto literal. La sintaxis para definir la clases es declarativa y fácil de leer. Las palabras clave como "has", "methods", "isa" y "after" son usadas para expresar diferentes aspectos de la clase.

Atributos


has: {
        alto: {is: "ro"},
        ancho: {is: "rw"},
    }, 

El primer elemento de la declaración de la clase Fotografía es un bloque "has" que define dos atributos de la clase: alto y ancho. El bloque alto: {is: "ro"} define "alto" como de sólo lectura. Mientras que el bloque ancho: {is: "rw"} define "ancho" como un atributo de lectura y escritura. Joose automáticamente crea los métodos getAlto() para "alto" y getAncho() y setAncho() para "ancho". El nombre de estos métodos sigue la convención camelCase, colocando la primera letra del atributo en mayúscula.

has: {
        etiqueta: {init: "yo"}
    }, 

El bloque etiqueta: {init: "yo"} define el atributo "etiqueta" con un valor por default que es el string "yo". Como no se especifica si es rw o ro, por defecto no se crean los métodos de acceso getEtiqueta() y setEtiqueta().

Métodos


methods: {
        clear: function () {
            this.alto = 0;
            this.setAncho(0);
        } 

El bloque "methods" define el método clear() para la clase Fotografía. Podemos poner todos los métodos que queramos. En este caso la función setea "alto" accediendo a la variable directamente, pero modifica "ancho" usando su método modificador creado con la declaración "rw".

Herencia


 isa: Fotografia, 

La cláusula "isa" en la definición de Selfie define que su super clase es Fotografía. Selfie hereda los métodos y atributos de su superclase.

Modificador de método


after: {
        clear: function () {
            this.etiqueta = "yo";
        }
    } 

Joose soporta los llamados modificadores de métodos. Uno de los 5 modificadores que declaran métodos con un comportamiento especial es "after". Aquí define que acciones ejecutar después de llamar al método con el mismo nombre definido en su superclase.

Inicialización


var foto= new Selfie({ancho: 360, alto:240}); 

El objeto literal {ancho: 360, alto:240} es pasado como argumento de un método especial llamada initialize() que lo usa para inicializar los valores del atributo del nuevo objeto.


viernes, 31 de julio de 2015

Construir un módulo Joose JS

Module(name,function)

La función global Module(name,function) hace que crear un namespace para las clases, roles y prototipos sea muy fácil. El módulo automáticamente crea el namespace llamado "name". Las clases que son creadas dentro de la función "function" serán puestas automáticamente dentro del namespace del módulo. Esto reduce el riesgo de conflictos de nombres. Un módulo proporciona una buena forma de estructurar y organizar el código que compone un proyecto (múltiples módulos) o una librería (normalmente un único módulo).

Module("com.test.module", function (m) {
    Class("Test", {
        methods: { world: function () { return "hello" } }
    });
    Class("Test2", {
        methods: { world: function () { return "hello" } }
    })
})

En el ejemplo la clase Test será globalmente conocida bajo el nombre "com.test.module.Test" y así se reduce el riesgo de conflictos de nombres.

jueves, 30 de julio de 2015

Construir una clase Joose JS

La función global Class(name, properties) crea una clase con el nombre "name". La clase es inicializada usando sus propiedades "properties" de esta manera:
  • isa: Indica de qué clase hereda, o sea, su superclase
  • does: Aplica roles a la clase
  • has: Crea atributos para la clase
  • methods: Crea los métodos de instancia
  • classMethods: Crea los métodos de clase
Existen también modificadores de métodos: before, after, around, override, augment

isa

Class("Avion", {
 isa: Transporte
})

En el ejemplo Avion heredará todos los métodos de la clase Transporte. No hay Herencia Múltiple.

does

Class("Pintura", {
 does: Coloreable
})

Aplica roles, a veces llamado traits (algo similiar a mixins), a la clase. Para aplicar múltiples roles se le pasa un array de roles.

has

Class("Puerta",{
 has: {
  color: {
   is: "rw",
   init: "blanca"
  },
  material: {
   is: "ro",
   init: "madera"
  }
 }
}

En el ejemplo la clase Puerta tiene dos atributos: color y material. El atributo "color" es de lectura/escritura y es inicializado a "blanca". El atributo "material" es de sólo lectura y es inicializado a "madera". Joose genera los métodos de acceso a los atributos automáticamente, en este caso se llamarían: getColor(), setColor(), getMaterial(). No hay un método setMaterial() porque fue declarado de sólo lectura.

methods

methods: {
 clear: function(){
  this.setX(0);
  this.setY(0);
 },
 stringify: function(){
  return "" + this.getX() + "," + this.getY()
 }
}

En el ejemplo agregamos dos métodos a la clase, los métodos clear() y stringify(). El primero para limpiar los atributos de la clase y el segundo para devolver un string que representa los valores de sus atributos.

classMethods

classMethods: {
 makeNew: function(){
  return new Punto3D()
 }
}

Funciona como "methods" pero para generar métodos de clase en vez de métodos de instancia. Ahora podemos crear un Punto3D llamando a Punto3D.makeNew()

Modificadores de métodos


Los métodos declarados como "before" son llamados antes del método que sobreescriben. El valor de retorno es descartado.
before: {
 clear: function(){ alert("Antes: " + this.stringify()) }
}

Los métodos declarados como "after" son llamados después del método que sobreescriben. El valor de retorno es descartado.
after: {
 clear: function(){ alert("Después: " + this.stringify()) }
}

Métodos especiales


Los objetos Joose devuelven el string "a ClassName" cuando se llama al método stringify(), siendo ClassName el nombre de la clase a la que pertenece el objeto. Éste método se puede sobreescribir. Algunos engines Js utilizan el método toString(), por eso no se modifica directamente toString(), Joose utiliza stringify().
Existe el método initialize() que Joose automáticamente utiliza para inicializar una instancia como esta: var point = new Point({x:10, y: 10})
Se lo puede sobreescribir para cambiar ese comportamiento. O podría ser útil definir un modificador "after" para el método initialize().

miércoles, 29 de julio de 2015

Clase Punto3D en Javascript usando Joose

Javascript


En Javascript vamos a implementar una clase Punto3D que hereda de la clase Punto implementada antes aquí.
// Implementamos una función para herencia
function inherit(superClass, subClass) {
    for(var i in superClass.prototype) {
        subClass.prototype[i] = superClass.prototype[i]
    }
}
Test.StandardPoint3D = function (x, y, z) {
    this.x = x || 0
    this.y = y || 0
    this.z = z || 0
}
// Hacemos que Test.Standard sea la super clase de Test.StandardPoint3D
inherit(Test.StandardPoint, Test.StandardPoint3D)
// No podemos asignar un nuevo prototipo porque ya tenemos uno de la super clase
Test.StandardPoint3D.prototype.getZ = function () {
    return this.z
}
Test.StandardPoint3D.prototype.setZ = function (z) {
    this.z = z;
}
var superMethod = Test.StandardPoint3D.prototype.clear;
Test.StandardPoint3D.prototype.clear = function () {
    superMethod.apply(this);
    this.z = 0;
}


Joose


Ahora reimplementamos la clase Punto3D usando la librería Joose y vemos que el nuevo código es más compacto y legible porque se ocupa de lo que nos importa.
Module("Test", function (m) {
    Class("Point3D", {
        isa: m.Point,
        has: {
            z: {
                is: "rw",
                init: 0
            }
        },
        after: {
            clear: function () {
                this.setZ(0)
            }
        }
    })
})

domingo, 26 de julio de 2015

Ejemplo de código Joose

Descargamos la libreria joose.js de https://code.google.com/p/joose-js/downloads/list y creamos este pequeño ejemplo llamado runpoint.html:


<!DOCTYPE html>
<html>
 <head>
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" >
  <script type="text/javascript" src="./joose.js"></script>
  <title>Joose Point</title>

  <script type="text/javascript">
  Class("Punto", {
   has: {
    x: {is: "rw"},
    y: {is: "rw"}
   },
   methods: {
    clear: function () {
     this.setX(0);
     this.setY(0);
    }
   }
  });

  Class("Punto3D", {
   isa: Punto,
   has: {
    z: {is: "rw"}
   },
   after: {
    clear: function () {
     this.setZ(0);
    }
   }
  });
  </script>

 </head>
 <body>

  <script type="text/javascript">
  var point = new Punto3D();
  point.setX(10);
  point.setY(30);
  var y = point.getY();
  point.z = 1;
  console.log("Un punto: ");
  console.log(point);
  console.log("var y: " + y);
  point.clear();
  console.log("Coordenada z luego de clear: " + point.getZ());
  var point2 = new Punto3D({ x: 10, y: 20});
  console.log("Coordenada y de point2: " + point2.y);
  </script>

 </body>
</html>

La salida en la consola del navegador es algo como esto:



runpoint.html:41 Un punto:
runpoint.html:42 f {x: 10, y: 30, z: 1}
runpoint.html:43 var y: 30
runpoint.html:45 Coordenada z luego de clear: 0
runpoint.html:47 Coordenada y de point2: 20

Clase Punto en Javascript usando Joose

Javascript


En Javascript vamos a implementar una clase Punto con los atributos x e y usando el namespace Test.
if(Test == null) {
    Test = {};
}
Test.StandardPoint = function (x, y) {
    this.x = x || 0
    this.y = y || 0
}
Test.StandardPoint.prototype = {
    getX: function () {
        return this.x
    },
    setX: function (x) {
        this.x = x
    },
    getY: function () {
        return this.y
    },
    setY: function (y) {
        this.y = y;
    },
    clear: function () {
        this.setX(0)
        this.setY(0)
    }
}

Joose


Ahora reimplementamos la clase Punto usando la librería Joose y vemos que el nuevo código es más corto y fácil de leer.
Module("Test", function (m) {
    Class("Point", {
        has: {
            x: {
                is:   "rw",
                init: 0
            },
            y: {
                is:   "rw",
                init: 0
            }
        },
        methods: {
            clear: function () {
                this.setX(0);
                this.setY(0);
            }
        }
    })
})

miércoles, 22 de julio de 2015

Qué es Joose

Qué es el framework Joose

Fuente del Joose

El código fuente de Joose es hosteado en GitHub

Joose

Es una librería open-source de JavaScript que soporta clases, herencia, mixins, traits y programación orientada a aspectos. Su sistema de objetos es multiparadigma, soporta el estilo de programación basado en clases y en prototipos. Joose se especializa en dotar al lenguaje JavaScript de técnicas de programación exitosas, por eso se lo usa a menudo con otros frameworks orientados al DOM/Ajax, como jQuery, YUI, Dojo, Prototype, Mootools y PureMVC.

Ejemplos de clases con Joose

A continuación implementamos dos clases con Joose: la clase Punto y la clase Punto3D
Class("Punto", {
    has: {
        x: {is: "rw"},
        y: {is: "rw"}
    },
    methods: {
        clear: function () {
            this.setX(0);
            this.setY(0);
        }
    }
});

Class("Punto3D", {
    isa: Punto,
    has: {
        z: {is: "rw"}
    },
    after: {
        clear: function () {
            this.setZ(0);
        }
    }
});
Punto3D es una subclase de Punto. Tiene un atributo más y un código adicional que corre antes del método clear() de su superclase. El valor "rw" significa que el atributo del objeto se de lectura y escritura, es decir que automáticamente se generan los métodos de acceso get() y set().

martes, 5 de junio de 2012

Una introducción agradable a Moose


Lo que sigue es la versión en español del artículo A gentle introduction to Moose escrita por Jay Kuri en el 2009.


Perl, desde el lanzamiento de su versión 5 en 1994, tiene las características de un lenguaje orientado a objetos. Pero estas características OO siguen siendo algo así como un "hágalo Usted mismo", con el clásico estilo de Perl, ofreciendo un mínimo de apoyo integrado en el lenguaje y el resto se deja a cargo de los demás. 

La principal ventaja de este estilo "hágalo Usted mismo" es que el lenguaje impone muy pocas restricciones sobre la manera de hacer las cosas. Por otro lado tiene la desventaja de ser algo intimidante con los novatos. Por lo bueno y lo malo, se ha vuelto familiar.

Otra ventaja es que las características tienen la libertad de evolucionar, por no estar sujetas por el lenguaje algunos programadores muy inteligentes tuvieron la libertad de explorar formas de hacer las cosas de maneras que no estaban preconcebidas. Moose es el resultado de ésta exploración y rápidamente se convirtió en el estandar defacto para la POO en Perl. Hoy vamos a explorar las bases de la creación y manipulación de objetos en Moose.

En la convencional Programación Orientada a Objetos en Perl hay tres cosas principales que necesitan hacerse. Estas son:
  1. Creación de objetos
  2. Atributos y métodos de acceso
  3. Herencia
Tomaremos un rápido exámen alrededor de estas cuestiones y las compararemos con la técnica Perl y la de Moose.


Creación de objetos
En puro Perl, la forma de crear un objeto es crear una referencia a una variable y luego "bendecirla" con una clase. Podemos hacer esto con cualquier tipo de variable, pero lo más común es usar una referencia a un hash. Esto se hace generalmente en una subrutina 'new':
package FooClass;

  sub new {
      my $class = shift;
      my $foo = {};
      bless $foo, 'FooClass';
      return $foo;
  }

Esto devuelve un objeto. Hay algo más aún. La forma Moose de hacer esto es algo más sencilla:
  package FooClass;
  use Moose;

Eso es todo. Moose crea la subrutina new() por nosotros. Si la clase tiene atributos, Moose también se encargará de gestionarlos basándose ​​en los argumentos que se pueden colocar.
Crear una instancia de una clase sigue la misma convención en un objeto de Moose como un objeto de puro Perl: simplemente llamar a new() en la clase. Moose, sin embargo, permite pasar los valores iniciales de sus atributos en la llamada. Por ejemplo:
  FooClass->new( name => 'bob' );
Este es un poco de funcionalidad útil y gratuita que nos brinda el uso de Moose.


Atributos y métodos de acceso
En Perl, nuestro objeto es (muy a menudo) un hash y sus atributos son simplemente miembros de ese hash. De nuevo a menudo, tales atributos se acceden directamente:
  $foo->{name};
Este generalmente está mal visto, ya que proporciona muy poca estructura y hace fácil declarar mal accidentalmente los atributos. $foo-> {naem} puede ser un error muy difícil de encontrar. La "mejor práctica" generalmente consiste en crear las subrutinas de acceso para las variables, lo que limita a los que utilizan el objeto para trabajar con los atributos que hay creados. (Los geeks OO se refieren a esto como "encapsulación"). El problema es que en Perl OO lo debemos crearlas nosotros mismos:
   sub name {
        my $self = shift;
        if( @_ ) {
            $self->{'name'} = $_[0];
        }
        return $self->{'name'};
    }

Se trata de una gran cantidad de código sólo para escribir los setter/getter del objeto. En puro Perl hay un módulo de CPAN nacido para hacer esto más fácil. Class::Accessor construye estos métodos por nosotros:
  package FooClass;
  use base qw(Class::Accessor);
  FooClass->mk_accessors(qw(name age));

Class::Accessor crea el método new por nosotros. Esto es claramente mejor que hacerlo a mano. Ahora es prácticamente imposible crear accidentalmente atributos o acceder a los equivocados. Hay una cosa que no hace bien. No le impide de ninguna manera poner basura en los atributos. Esto es perfectamente legal:
  $foo = FooClass->new();
  $foo->name(192);
  $foo->age('magdalena');

Moose, por el contrario, no sólo hace lo que Class::Accessor, sino que añade la comprobación de tipos (y algunas otras cosas). El mismo objeto creado con Moose:
  package FooClass;
  use Moose;
  has 'name' => (
    is => 'rw',
    isa => 'Str'
  );

  has 'age' => (
    is => 'rw',
    isa => 'Int'
  );
  1;

Lo anterior proporciona el mismo name() y age() que estamos acostumbrados. Pero si tratamos de establecer la edad como 'magdalena' ahora vamos a obtener un error. Por otro lado también tenemos la capacidad de decir esencialmente "este atributo no se puede cambiar después de crear el objeto". Entre otras cosas, el sistema de atributos y de control de tipos de Moose es increíblemente flexible y merece su propio tutorial dedicado.


Herencia
La herencia en programación orientada a objetos está diseñada para permitir la especialización de una clase. El ejemplo clásico es que se puede tener una clase Figura que puede proporcionar un cierto grado de funcionalidad, y cuando se necesita una clase Cuadrado se puede heredar de Figura y añadir sólo el código que hace particular al Cuadrado. En Perl "puro" OO podríamos hacer esto:
  package Cuadrado;
  @ISA = ("Figura");
  # el resto de la clase Cuadrado

Perl tiene la inteligencia para buscar los métodos que no encuentra en la clase Cuadrado en las clases definidas en @ISA. Funciona bien, pero no es muy intuitivo. Moose tiene herencia también, y lo hace más evidente diciendo:
  package Cuadrado;
  use Moose;
  extends 'Figura';
  # el resto de la clase Cuadrado

Bastante sencillo


Otras cosas de Moose
Moose no hace nada que no se pueda hacer con Perl OO. Moose se basa en las mismas características OO soportadas por el lenguaje Perl. Se ocupa, sin embargo, de una enorme cantidad de trabajo que de lo contrario tendríamos que hacer nosotros mismos, dándole la libertad para trabajar en su "nueva" funcionalidad en lugar de reinventar la rueda una vez más.

En este artículo he mostrado cómo hacer las cosas "normales" de Perl OO con Moose. En este punto, usted sabe cómo hacer uso de la programación orientada a objetos básica y podría comenzar a reemplazar sus enrolladas clases hechas a mano por otras construidas con Moose.

Moose, sin embargo, es más que un poco de sintaxis inteligente y algunos ahorros de tiempo. Moose tiene algunas características adicionales que lo hacen realmente increíble para trabajar con él. Sólo voy a referirme a ellas aquí, ya que requeriría un libro entero para cubrirlas adecuadamente. Algunas de las características disponibles con Moose son las siguientes: 
  • Metadatos de la clase: La posibilidad que tiene su código de examinar la estructura de sus objetos.
  • Coerción: La capacidad de convertir los valores de un tipo a otro cuando sea necesario.
  • Modificadores de métodos: La capacidad de agregar código que se ejecuta antes, después o alrededor de un método existente.
  • Roles: La capacidad de agregar funcionalidad predefinida a las clases sin usar herencia.
Hay muchas otras que vale la pena investigar también. Los roles son especialmente interesantes y proporcionan una flexibilidad que no tiene precedentes en casi cualquier lenguaje orientado a objetos. También digno de mención son las extensiones de Moose que proporcionan una funcionalidad incluso más allá de Moose estándar.

Para obtener más información sobre Moose, eche un vistazo a la documentación. Para ver más en detalle Moose vs Perl OO, eche un vistazo a la versión "sin azúcar" del manual.

También puede consultar la página de inicio de Moose. Por último, he comenzado una lista de "Trampas de Moose" en Catalyzed Wiki para rastrear algunas de las partes más difíciles de Moose que he encontrado. Siéntase libre de agregar las propias, a medida que descubre los placeres de usar Moose.