Sobre las Interfaces en Ruby

Lo primero es que no existe tal cosa como una interfaz en Ruby como sí ocurre en otro lenguaje orientado a objetos, Java.

En todo caso, hay formas de intentar emular ese mecanismo pero antes vamos a definir que es una interfaz para tener un concepto claro.

¿Qué es una Interfaz?

Es una especie de contrato o descripción que una clase se «compromete» a tener al implementar(usar) dicha interfaz. Este contrato está dado por una colección de métodos abstractos(sin definir su funcionalidad) los cuáles deben ser implementados en la clase que se adhiere a la interfaz.

Un ejemplo de interfaz en Java:

interface Animal {
   public void eat();
   public void travel();
}

La interfaz Animal define dos métodos: eat() y travel() pero sin nada definido. Ahora, toda clase que decida implementar esa interfaz, deberá tener esas dos funciones reescribiéndolas con el código a ejecutar.

public class Dog implementas Animal {
  public void eat() {
    System.out.println("Woof instead of yum");
  }

  public void travel() {
    System.out.println("Riding bike");
  }
}

Se usa la palabra reservada implements para denotar que una clase está firmando el contrato con la interfaz definida.

Muy bien. Lindo todo pero eso es en Java y no en Ruby. Como ya decía al inicio, este lenguaje no tiene tal característica, sin embargo, podemos «imitarla» de ciertas formas.

Imitando Interfaz en Ruby con raise

Esta forma sería usando un módulo con métodos vacíos cuyo cuerpo sea levantar una excepción al ser enviados a objetos.

module Animal
  def eat
    raise 'Not implemented'
  end

  def travel
    raise 'Not implemented'
  end
end

Ahora, toda clase que incluya ese módulo deberá definir y sobre escribir el cuerpo del método para evitar levantar la excepción.

class Cat
  include Animal

  def eat
    puts 'The cat is eating'
  end
end

Esto es una forma, no la mejor, en algunas situaciones no ideal, pero bueno, ya sabemos que existe o por lo menos es una manera de intentar documentar intención para ciertos métodos.

una interfaz

Imitando Interfaz en Ruby con duck typing

Otra forma es valiéndose de duck typing en Ruby. ¿Qué es eso de duck typing? Es una premisa que indica que un objeto debe responder a mensajes indiferentemente de si pertenece a una clase u otra.

Este concepto sirve mucho para evitar usar condicionales a la hora de enviar mensajes a objetos. Un ejemplo un poco simple de esto sería:

cat.meow if cat.is_a?(Cat)

La línea anterior envía el mensaje meow al objeto cat solo si este es una instancia de la clase Cat. Bien, lo que nos dice el señor duck typing es que ese condicional está demás y mal. Tal objeto debería tener una respuesta adecuada a ese mensaje, sea un maullido o una excepción.

Pues bien, la idea de valerse de duck typing para tratar de emular una interfaz se cumple ya que de cierta forma se está cumpliendo el contrato de la implementación. Si el objeto cat responde a meow significa que la clase Cat implementa dicho método.

Imitando Interfaz en Ruby con tests

Finalmente, se puede imitar una interfaz valiéndose de tests unitarios. La forma es que los tests tendrían que pasar para que el código tenga un nivel de validez adecuado, o sea que se estaría cumpliendo el contrato entre la clase y la «interfaz».

describe Cat do

  before { @cat = described_class.new }

  describe '#meow' do
    it 'meows' do
      expect(@cat.meow).to be_a(String) 
    end
  end
end

Generalmente, los tests sirven como documentación y en este caso como firma del contrato con la interfaz.

En definitiva, Ruby no cuenta con algunas características de otros lenguajes, sin embargo, la flexibilidad del lenguaje permite improvisar o arreglarselas para lograrlo.

Autor: cesc1989

Ingeniero de Sistemas que le gusta escribir y compartir sobre recursos que considera útiles, además que le gusta leer manga y ver anime.

Deja un comentario

Este sitio utiliza Akismet para reducir el spam. Conoce cómo se procesan los datos de tus comentarios.