Overblog Seguir este blog
Edit post Administration Create my blog
10 febrero 2014 1 10 /02 /febrero /2014 15:26

Hola hoy día vamos a tener unos temas que nos van a ayudar a manejar mejor nuestro código en Ruby, también estos temas son parte de la programación orientada a objetos.

 

Módulos

 

Un módulo nos permite agrupar generalmente clases y funciones o subrutinas, para poder utilizarlos posteriormente, se declara con module, el nombre de módulo debe empezar con maúsculas y se termina con un end, en el medio debe estar nuestro código:

 

irb(main):350:0> module Herramientas

irb(main):351:1>  VERSION = 1.1

irb(main):352:1>  def Herramientas.sumar a, b

irb(main):353:2>   a + b

irb(main):354:2>  end

irb(main):355:1>  def self.restar a, b

irb(main):356:2>   return a - b

irb(main):357:2>  end

irb(main):358:1> end

=> nil

 

Bueno en este ejemplo vemos en la linea 350 que se ha declarado el módulo "Herramientas" con el uso de "module", luego en la linea 351 se ha creado una constante VERSION, luego vemos que se ha creado un método "sumar", pero observamos que esta escrito como Herramientas.sumar, osea tiene el nombre del módulo mas un punto y seguidamente del método, esto indica que ese método es usable directamente desde el módulo; Acto seguido vemos en la linea 355 que se crea el método restar, pero observamos que hay un "self." ese self es como un reemplazo de Herramientas (para no tener que escribir el nombre del módulo) y es casi lo mismo que haber escrito "Herramientas.restar" pero hay que tener cuidado ya que self cambia de acuerdo al contexto del escenario, por lo que solo funcionará cuando lo llamemos dentro de su módulo, vemos en la línea 356 el uso de "return" pero es opcional, puede haber quedado simplemente como a - b.

 

Para usar el módulo directamente, hacemos lo siguiente:

 

irb(main):359:0> Herramientas.sumar 5, 2

=> 7

irb(main):360:0> Herramientas.restar 5, 2

=> 3

irb(main):361:0> Herramientas::VERSION

=> 1.1

irb(main):362:0> Herramientas::restar 5, 2

=> 3

 

Vemos que estamos usando los métodos sumar y restar directamente desde el módulo Herramientas, pero en la línea 361 vemos un operador nuevo, los cuatro puntos :: este operador nos sirve para accesar a las constantes, métodos, clases y otros módulos. Pero solo podemos hacer eso desde módulos o clases.

 

Herencia

 

En Ruby, el creador de este lenguaje ha preferido, por temas de diseño y practicidad, utilizar la herencia simple y usar MixIN para reemplazar la herencia múltiple, nos asegura que nos quita un dolor de cabeza 

 

Para realizar la herencia simplemente se usa el símbolo < (menor que) y este símbolo " < " se debe usar al declarar una nueva clase:

 

irb(main):367:0> class Lobo

irb(main):368:1>  def aullar

irb(main):369:2>   "Auuuuuu"

irb(main):370:2>  end

irb(main):371:1> end

=> nil

irb(main):372:0> class Perro < Lobo

irb(main):373:1>  def ladrar

irb(main):374:2>   "Guau!"

irb(main):375:2>  end

irb(main):376:1> end

=> nil

irb(main):377:0> chihuahua = Perro.new

=> #<Perro:0x000000044d8e70>

irb(main):378:0> chihuahua.ladrar

=> "Guau!"

irb(main):379:0> chihuahua.aullar

=> "Auuuuuu"

 

Como podemos ver, se ha creado una clase Lobo que tiene el método aullar, luego en la línea 372, hemos creado la clase Perro, pero esta "hereda" de la clase Lobo, la clase perro tiene solamente el método ladrar, pero al heredar de su ancestro Lobo, entonces tambien va a poder "aullar", osea utilizar el método aullar de la clase Lobo de la cual ha heredado, por eso hemos instanciado un Chihuaha de la clase Perro, pero este Chihuahua puede ladrar y también puede aullar (por herencia, se puede decir que Perro es una subclase de Lobo).

 

irb(main):381:0> chihuahua.class

=> Perro

irb(main):384:0> chihuahua.instance_of? Perro

=> true

irb(main):385:0> chihuahua.instance_of? Lobo

=> false

irb(main):386:0> chihuahua.kind_of? Lobo

=> true

irb(main):387:0> chihuahua.kind_of? Perro

=> true

irb(main):388:0> chihuahua.is_a? Perro

=> true

irb(main):389:0> chihuahua.is_a? Lobo

=> true

irb(main):433:0> Perro.superclass

=> Lobo

 

Como se puede ver, aqui hay unos métodos interesantes, en la linea 381 preguntamos de que clase es el chihuahua y nos dice que es un Perro, luego en la 384 le preguntamos si este chihuahua ¿es una instancia de Perro? (instance_of) y nos dice que si, le preguntamos en la 385 si ¿es una instancia de Lobo? y nos dice que no, pero en la 386 le preguntamos si el chihuahua ¿es una especie o tipo de lobo? (kind_of) y nos dice que sí, ya que el Perro es una subclase de Lobo, así que el Perro es una especie de Lobo (por increible que sea), ahora en las líneas 388 y 389 el método is_a? es un sinónimo de kind_of?, es decir son lo mismo; también en la línea 433 el superclass devuelve cual es la clase padre de la clase Perro.

 

MixIN (reemplazo de herencia múltiple)

 

Bueno ahora bien lo bueno, el MixIN es para poder utilizar otros módulos (que pueden contener otras clases y/o modulos) dentro de una clase o módulo, de tal manera que se reutiliza funcionalidad. Ahora veamos el módulo anterior:

 

irb(main):395:0> module Herramientas

irb(main):396:1>  VERSION = 1.1

irb(main):397:1>  def Herramientas.sumar a, b

irb(main):398:2>   a + b

irb(main):399:2>  end

irb(main):400:1>  def self.restar a, b

irb(main):401:2>   return a - b

irb(main):402:2>  end

irb(main):403:1>  def multiplicar

irb(main):404:2>    "no implementado"

irb(main):405:2>  end

irb(main):406:1> end

=> nil

 

Hemos añadido el método multiplicar al módulo Herramientas (línea 403) pero observamos que simplemente es "def multiplicar" y no es "def self.multiplicar" ni "def Herramientas.multiplicar", lo cual significa que ese método solo se puede usar en una instancia; ¿Pero se puede crear una instancia de un módulo? la respuesta es no!, entonces viene otra pregunta ¿en que momento se puede usar ese método si no se puede crear instancias de un módulo? o de otra manera ¿que sentido tiene definir métodos de instancia en el módulo si no se puede crear una instancia del módulo?, pues la solución es que solamente se puede si la "mezclamos", es decir, si realizamos el MixIN:

 

irb(main):413:0> class Calculadora

irb(main):414:1>  extend Herramientas

irb(main):415:1>  def que_realiza?

irb(main):416:2>   "operaciones"

irb(main):417:2>  end

irb(main):418:1> end

=> nil

irb(main):211:0> Calculadora.multiplicar

=> "no implementado"

 

Con el extend de la línea 414, nos sirve para que la clase Calculadora (no las instancias) pueda obtener los métodos de instancia del módulo (osea solo el "def multiplicar"), y en la línea 211 se ve que llamamos a ese método "multiplicar"; Pero desde la clase no podemos acceder directamente a la constante VERSION, y en una instancia de Calculadora tampoco podremos acceder a nada del módulo Herramientas, entonces para ello realizamos el MixIN:

 

Haciendo MixIN

 

irb(main):221:0> class Calculadora

irb(main):222:1>  extend Herramientas

irb(main):223:1>  include Herramientas

irb(main):224:1>  def que_realiza?

irb(main):225:2>   "operaciones"

irb(main):226:2>  end

irb(main):227:1> end

=> nil

irb(main):229:0> Calculadora::VERSION

=> 1.1

 

Ahora que se ha realizado el MixIN, la clase Calculadora ya puede acceder a la constante VERSION del módulo Herramientas, pero no solamente eso, sino que ahora las instancias de Calculadora pueden acceder:

 

irb(main):233:0> calc = Calculadora.new

=> #<Calculadora:0x2dd1c28>

irb(main):237:0> calc.multiplicar

=> "no implementado"

irb(main):238:0> calc.que_realiza?

=> "operaciones"

 

Ahora vamos a crear un módulo especial

 

irb(main):239:0> module Plus

irb(main):240:1>  def graficos_avanzados

irb(main):241:2>   true

irb(main):242:2>  end

irb(main):243:1> end

=> nil

 

Y vamos a crear una clase CalculadoraCientifica que heredará de Calculadora y hará un MixIN con el módulo Plus (hay que considerar que Calculadora tiene MixIN con Herramientas)

 

irb(main):261:0> class CalculadoraCientifica < Calculadora

irb(main):262:1>  include Plus

irb(main):263:1>  def que_realiza?

irb(main):264:2>   "realiza: #{super}, graficos"

irb(main):265:2>  end

irb(main):266:1> end

=> nil

irb(main):267:0> casio = CalculadoraCientifica.new

=> #<CalculadoraCientifica:0x30645d8>

irb(main):268:0> casio.que_realiza?

=> "realiza: operaciones, graficos"

irb(main):269:0> casio.graficos_avanzados

=> true

irb(main):270:0> casio.multiplicar

=> "no implementado"

 

Como se puede ve en la linea 262 hemos hecho un MixIN con Plus, y hemos obtenidos las funcionalidades de Plus (los métodos de instancia), ahora en la línea 264 se ve que estamos devolviendo una cadena de texto o string, y usamos el #{} ("michi" o numeral y llaves) que sirven para reemplazar por alguna variable en su interior, y en el interior usamos la palabra clave "super" que significa que va a utilizar el método "que_realiza?" pero de la clase padre Calculadora, luego como esta devuelve un string "operaciones" y reemplazando obtenemos "realiza: operaciones, graficos"; luego también heredamos los métodos MixIN de Calculadora del módulo Herramientas como el método de instancia "multiplicar".

 

Ahora también podemos usar el método:

 

irb(main):271:0> CalculadoraCientifica.ancestors

=> [CalculadoraCientifica, Plus, Calculadora, Herramientas, Object, Kernel, BasicObject]

 

Que nos devuelve un array conteniendo las clases y/o módulos que "arman" a la clase CalculadoraCientifica, empieza por la misma clase, luego el módulo Plus, luego la clase Calculadora y el módulo Herramientas, las otras clases Object, Kernel, BasicObject, son añadidas tanto por el lenguaje Ruby como por el IRB.

 

Es importante que primero Ruby buscará los métodos en su propia clase CalculadoraCientifica, si no lo encuentra proseguirá en buscar en Plus, si no lo encuentra proseguirá en buscar en Calculadora y luego en Herramientas.

 

Para las clases, el último método sobreescribe al primero, como se vió en la línea 264, se volvio a sobreescribir el método que_realiza? se debe considerar como concepto vertical de sobreescritura de métodos en herencias y MixIN.

 

Muy bien, culminamos este interesante capítulo, hasta aqui vamos con el capitulo 17 y sugiero que lo lean varias veces y practiquen ya que este tema es un pilar para los diversos frameworks y utilidades escritas en Ruby, el siguiente capítulo es el número 18, cualquier duda pueden comentar y sera absuelto, no tienes que registrarte ni realizar nada adicional para comentar, soy su amigo!.

Compartir este post

Repost 0
Published by Daniel A. Nuñez C. - en Tutorial Ruby
Comenta este artículo

Comentarios

Presentación

  • : El blog de Daniel A. Nuñez C.
  • El blog de Daniel A. Nuñez C.
  • : Un blog sobre tecnologías y futuro, también sobre lenguaje de programación Ruby y más.
  • Contacto

Perfil

  • Daniel A. Nuñez C.
  • Ingeniero de Sistemas
  • Ingeniero de Sistemas

Donaciones/Donations

Por favor considera realizar una donación

Please make a donation

btn_donateCC_LG.png

Buscar Tema En Este Blog

Archivos