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