POO en ruby parte II

Carlos Torrealba
Academia Hack
Published in
4 min readJun 12, 2019

Herencia, encapsulamiento y módulos

La programación orientada a objetos es y sigue sido bastante usada en el mundo del software hoy en día, es por eso que veremos algunas otras características que nos brida Ruby como lenguaje.

Si estás iniciando en el mundo de la programación y todavía desconoces algunos conceptos te recomiendo que leas primero este artículo:

Herencia

El la vida cotidiana una herencia puede significar algo muy bueno o muy malo. Podemos heredar una fortuna o muchísimas deudas, lo cierto es que la herencia comúnmente nos permiten transmitir, bienes, derechos y obligaciones, así podemos acceder a elementos que antes no teníamos y por ende extiende nuestro alcance.

El la programación orientada a objetos (POO) la herencia facilita la creación de objetos a partir de otros ya existentes e implica que una subclase obtiene todo el comportamiento (métodos) y eventualmente los atributos (variables) de su superclase. (wiki)

El propósito de la herencia, es crear versiones especializadas de una clase, veamos un ejemplo:

Food -> Fruit -> Orange

Como podemos ver la clase padre (superclass) siempre es más genérica que las subclases

Una de las características más notables es la herencia de comportamiento veamos un ejemplo real:

Tanto como TextDocument como HTMLDocument heredan de Document , esto les permite a las instancias de ambas acceder a los métodos definidos en Document

html = HTMLDocument.new(name: hello_word, encode: 'utf-8', readonly: false)
html.name
=> "hello_world"
html.print
=> "Parsing"
=> "Printing document"
html.full_name
=> "hello_world.html"

Algo que habrás notado es la palabra reservada super , esto no es más que un método que solo se puede ejecutar dentro de un método y que tiene como función ejecutar el método de la superclase con el mismo nombre.

El primer ejemplo que notamos es que super fue invocado desde el initialize de TextDocumety HTMLDocument, aquí super busca el método initialize en la superclase es decir en Document y simplemente le pasa a Document todos los argumentos que le fueron inyectados a las instancias de las clases TextDocument y HTMLDocument

Una característica interesante de super es que puede pasarle argumentos específicos a la superclase como se puede notar en el initialize de HTMLDocument

Y podemos usar el retorno de super ser reutilizado por nuestros métodos de instancia como en el caso de full_name

Encapsulamiento

  • Métodos públicos: Los métodos públicos son todos métodos accesibles para cualquier instancia externa a la clase. Un ejemplo de ello es nuestros método name :
text = TextDocument.new(readonly: false)
text.name
=> "unnamed"

Hasta ahora solo hemos definido métodos públicos en los ejemplos anteriores, veamos como definir métodos privados

  • Métodos privados: Algunas veces queremos tener métodos que solo puedan ejecutare dentro de la definición de la clase, métodos que sirvan de apoyo para crear métodos públicos y nos permitan organizar mejor nuestro código. Hagamos un cambio en uno de los ejemplos anteriores para visualizar que se quiere lograr:

Convertimos el método parse en un método privado, pero para ello utilizamos la palabra reservada private . Así que todo método que se defina debajo de la palabra reservada private se convertirá en un método privado. Entonces ¿seguirá funcionando el método print ?

html = HTMLDocument.new(encode: "utf-8", readonly: false)
html.print
=> Parsing
=> Printing document

¡Funciona!, ¿qué pasaría si llamamos la método parse directamente?

html.parse
NoMethodError (private method `parse' called for #<HTMLDocument:0x00005618e7b29278>)

El método parse ya no es accesible más desde fuera de la definición de la clase.

  • Métodos protegidos: Los método públicos y los métodos privados son los más comunes a la hora de escribir nuestro código, pero Ruby presenta una característica interesante para otras situaciones no tan comunes. Imaginemos que queremos tener una combinación entre un método público y un método privado, para ellos nuestro método “protegido” debe seguir al menos estas dos reglas.
  1. Desde afuera de nuestra class, el método protected se comporta como un método privado
  2. Desde dentro de nuestra clase, el método protected es accesible como un método public

Aquí un ejemplo:

Aquí podemos ver como el método protegido es accesible dentro de la clase y podemos acceder a su información:

fido = Animal.new 
fido.a_public_method
=> Will this work? Yes, I'm protected!

Este ejemplo demuestra la segunda regla, no se puede llamar un método protegido desde fuera de la clase:

fido.a_protected_method
=> NoMethodError: protected method `a_protected_method' called for #<Animal:0x007fb174157110>

Módulos

Los módulo es una de las características más interesantes de Ruby, Se pueden usar para añadir un comportamiento especifico a nuestras clases, también pueden usarse para organizar el código que usamos y aplicar técnicas de composición en lugar de herencia.

Veamos algunos ejemplos:

Include:

Incluir métodos a nuestras clases es la forma más común de usar los módulos, cuando llamamos include en la definición de la clase, Ruby inserta nuevos métodos disponibles únicamente para las instancia de dicha clase:

Los métodos render_pdf y render_csv son incluidos en la clase Document es por eso que toda instancia de Document y toda instancia de HTMLDocument (porque hereda de Document ) podrán tener acceso a ellos:

document = Document.new(readonly: false)
document.print_csv
=> "rendering in csv file: unnamed"
html = HTMLDocument.new(name: 'example', encode: 'utf-8', readonly: false)
html.print_pdf
=> "rendering in pdf file: example.html"

Extend:

Usar extend en la clase importará como métodos de clase los métodos definidos en el modulo

document = Document.new(readonly: false)
Document.destroy(document)
=> "Destroying #{unnamed}"

Usar herencia, principios de encapsulamiento y módulos son clave para desarrollar programas mantenibles, escalables y participativos. Si nuestro código está bien organizado, cuando alguien quiera colaborar en él no sufrirá tratando de entender como interactúa cada parte de nuestro código.

Photo by Markus Spiske on Unsplash

--

--