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

sábado, 8 de agosto de 2015

Clase Cuenta Bancaria en JS usando Joose


Problema

Modelizaremos una cuenta bancaria normal. En esta cuenta se puede depositar dinero, retirar dinero y comprobar su saldo actual. No se puede retirar más dinero que el que hay en la cuenta. Además modelizaremos una cuenta corriente con una protección contra sobregiros opcional. La protección contra sobregiros protegerá al propietario de la cuenta corriente retirando automáticamente los fondos necesarios de la cuenta de sobregiro para asegurar que un cheque no rebotará.

Solución

Module("Banco", function (m) {
  Class("Cuenta", {
    has: {
      balance: {
        is: "rw",
        init: 0
      }
    },
    methods: {
      depositar: function (monto) {
        this.setBalance(this.getBalance() + monto)
      },
      retirar: function (monto) {
        if(this.getBalance() < monto) {
          throw "Cuenta sobregirada"
        }
        this.setBalance(this.getBalance() - monto);
        return this.getBalance();
      }
    }
  });
  
  Class("CuentaCorriente", {
    isa: m.Cuenta,
    has: {
      cuentaSobregiro: {
        isa: m.Cuenta,
        is: "rw"
      }
    },
    before: {
      retirar: function (monto) {
        var cantidadEnRojo = monto - this.getBalance()
        
        if(this.cuentaSobregiro && cantidadEnRojo > 0) {
           this.cuentaSobregiro.retirar(cantidadEnRojo);
           this.depositar(cantidadEnRojo);
        }
      }    
    }
  })
}) 

Explicacion

La clase Cuenta tiene un "balance" inicializado en 0 y dos métodos: "depositar" y "retirar". La CuentaCorriente es una subclase de Cuenta que tiene una "cuentaSobregiro" opcional que es de tipo Cuenta. Antes de retirar un monto de la CuentaCorriente verifica si puede sobregirar la cuenta.

Módulos

Module("Banco", function (m) {
...
} 

La función Module() crea el namespace "Banco". Toma como segundo argumento una función que crea las clases Cuenta y CuentaCorriente. La función obtiene un objeto módulo como parámetro, que más tarde será utilizado para facilitar el acceso a otras clases ubicadas dentro del namespace.

Restricciones de Tipo

has: {
  cuentaSobregiro: {
    isa: m.Cuenta,
    is: "rw"
  }
}, 

Aquí introducimos un nuevo atributo para la clase CuentaCorriente llamado "cuentaSobregiro". Usando la palabra clave isa ponemos una restricción de tipo sobre el atributo. Esta restricción es chequeada cada vez que el método setCuentaSobregiro() es usado. Ese método fue creado automáticamente cuando se definió el atributo como rw.

Modificador de método "before"

before: {
  retirar: function (monto) {
    var cantidadEnRojo = monto - this.getBalance()
    
    if(this.cuentaSobregiro && cantidadEnRojo > 0) {
       this.cuentaSobregiro.retirar(cantidadEnRojo);
       this.depositar(cantidadEnRojo);
    }
  }    
} 

Introducimos un método que será ejecutado antes del método retirar(). De esta manera el método original se ve aumentado en su comportamiento. Si el dinero actual en el balance de la cuenta no es suficiente para el retiro, se extrae lo que falta de la cuentaSobregiro y se deposita en la cuenta.

Modificador de método "override"

Otra posible implementación podría haber sido sobreescribir el método retirar() usando el modificador override, el cual permite llamar al método de la superclase haciendo this.SUPER()
override: {
  retirar: function (monto) {
    var cantidadEnRojo = monto - this.getBalance()
      
    if(this.cuentaSobregiro && cuentaSobregiro > 0) {                
      this.cuentaSobregiro.retirar(cantidadEnRojo);
      this.depositar(cantidadEnRojo);
    }

    this.SUPER(amount)
  }
} 

Instanciación de los objetos

Todos los objetos Joose reciben un inicializador estándar que permite inicializar los objetos usando argumentos por nombre en el constructor:
var cajaAhorros= new Banco.Cuenta({ balance: 100 });
var cuentaCorriente= new Banco.CuentaCorriente({ 
    balance:         200, 
    cuentaSobregiro: cajaAhorros
});
console.log("Una cuenta: ");
console.log(cajaAhorros);
console.log("Una cuenta corriente: ");
console.log(cuentaCorriente);
console.log("Operamos en la cuenta con un retiro parcial de 100");
cuentaCorriente.retirar(100);
console.log(cuentaCorriente);
console.log(cajaAhorros);
console.log("Sobregiramos la cuenta con un retiro mayor: 150");
cuentaCorriente.retirar(150);
console.log(cuentaCorriente);
console.log(cajaAhorros);
console.log("Sobregiramos demasiado la cuenta: 300");
cuentaCorriente.retirar(300);

Una cuenta: 
 a Banco.Cuenta { balance=100, meta=a Joose.Class, initialize=initialize(), más...}
Una cuenta corriente: 
 a Banco.CuentaCorriente { balance=200, cuentaSobregiro=a Banco.Cuenta, meta=a Joose.Class, más...}
Operamos en la cuenta con un retiro parcial de 100
 a Banco.CuentaCorriente { balance=100, cuentaSobregiro=a Banco.Cuenta, meta=a Joose.Class, más...}
 a Banco.Cuenta { balance=100, meta=a Joose.Class, initialize=initialize(), más...}
Sobregiramos la cuenta con un retiro mayor: 150
 a Banco.CuentaCorriente { balance=0, cuentaSobregiro=a Banco.Cuenta, meta=a Joose.Class, más...}
 a Banco.Cuenta { balance=50, meta=a Joose.Class, initialize=initialize(), más...}
Sobregiramos demasiado la cuenta: 300
uncaught exception: Cuenta sobregirada

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().