15. Go to go: interfaces y métodos

Publicado por

Golang nos permite trabajar con métodos, la principal diferencia entre estos y las funciones es que, a diferencia de estas últimas, un método permite que se construyan diferentes algoritmos para tipos de registros diferentes bajo un mismo identificador; también se puede utilizar una función que decida cuál método ejecutar en base al tipo de registro que se le pase como argumento. Fuera de esas diferencias, un método en Go es una función que realiza operaciones referentes al comportamiento de un registro. Para más información referente a los métodos, consultar aquí.

¿Qué es una interfaz?

Una interfaz es una colección de firmas de métodos, es decir, son declaraciones de métodos sin cuerpo (código interior o algoritmo), una firma de método es el equivalente al prototipo de una función en lenguajes como C. Las interfaces son muy útiles para visualizar fácilmente qué recibe de argumentos uno o varios métodos, para construirlos más adelante según se requiera, crear diferentes cuerpos con un mismo identificador, entre otras cosas.

La siguiente es la sintaxis de declaración de una interfaz en Go:

Tipo_interfaz = "interface" "{" { Especificación_método ";" } "}"
Especificación_método = Nombre_método Firma | Nombre_tipo_interfaz
Nombre_método = identificador
Nombre_tipo_interfaz = Nombre_tipo

Nota: más información al respecto aquí.

¿Cómo utilizar interfaces?

El primer paso para utilizar interfaces es, aunque suene obvio, identificar la situación en que pueden ser de beneficio. Cualquier código pensado para utilizar interfaces es posible escribirlo sin necesidad de incluirlas, es por ello que saber identificar el caso adecuado es tan importante como saber usarlas. En este caso supongo que deseo almacenar información de figuras geométricas, las cuales, comparten métodos que se pueden consultar en todas ellas pero con algoritmos diferentes para cada una, como lo es el cálculo del área. Independientemente de que se trabaje con rectángulos, círculos, trapecios etc. todas las figuras geométricas permiten calcular su área aunque de forma distinta para todas ellas. La siguiente es una interfaz tipo FiguraGeometrica que contiene un método que devuelve el área de la figura:

type FiguraGeometrica interface {
  area() float64
}

En seguida se declaran los miembros que trabajaran con la interfaz. Las figuras serán registros de tipo diferente. En mi caso he decidido que para ejemplificar el funcionamiento solamente usaré rectángulos y trapecios:

type Rectangulo struct {
  /* Información de rectángulos */
  base, altura float64
}

type Trapecio struct {
  /* Información de trapecios */
  base_mayor, base_menor, altura float64
}

Nota: en Golang no hay objetos como en Java o C++, por eso se trabaja con registros (struct). Una vez que se han declarado las figuras, construimos el método area() para cada una de ellas, este recibirá de argumento un registro del tipo de figura de la que deseemos calcular su área:

func(figura Rectangulo) area() float64 {
  return figura.base * figura.altura
}

func(figura Trapecio) area() float64 {
  return (figura.base_mayor + figura.base_menor) * figura.altura / 2
}

Se puede crear una función que acceda al método si así se desea. Para ejemplificar utilizaremos la función dameArea() que recibe de argumento un registro tipo FiguraGeométrica que en realidad será del tipo de figura que deseamos consultar su área pero enmascarado. Go determina a qué método area() deseamos acceder dependiendo del tipo real de ese argumento:

func dameArea(fig FiguraGeometrica) float64 {
  return fig.area()
}

No es necesario crear la función dameArea() ya que podemos utilizar de forma directa el registro para llamar al método, suponiendo que deseamos imprimir lo que este devuelve podemos hacer lo siguiente:

fmt.Println(trapecio.area())

Nota: ambos modos de acceso a métodos (con función o con registro) son validos, su uso depende del programador y de las necesidades del proyecto. El siguiente es el ejemplo funcional completo incluyendo el llamado a cada método desde el main:

package main
import "fmt"

/* Declaración de una interfaz tipo FiguraGeométrica*/
type FiguraGeometrica interface {
  area() float64
  //Aquí podrían ir más métodos
}

/* Declaración de registro tipo Rectangulo */
type Rectangulo struct {
  base, altura float64
}

/* Declaración de registro tipo Trapecio */
type Trapecio struct {
  base_mayor, base_menor, altura float64
}

/* Método para los registros Rectangulo implementando la interfaz */
func(figura Rectangulo) area() float64 {
  return figura.base * figura.altura
}

/* Método para los registros Trapecio implementando la interfaz */
func(figura Trapecio) area() float64 {
  return (figura.base_mayor + figura.base_menor) * figura.altura / 2
}

/* Definición de un método para Figura */
func dameArea(fig FiguraGeometrica) float64 {
  return fig.area()
}

func main() {
  rectangulo := Rectangulo {base: 4, altura: 7.5}
  trapecio := Trapecio {base_mayor: 5, base_menor: 2, altura: 3}

  /* Llamado a función dameArea() */
  fmt.Printf("Area del rectángulo: %f\n", dameArea(rectangulo))

  /* Uso del registro para llamar a area() */
  fmt.Printf("Area del trapecio: %f\n", trapecio.area())
}

Salida:

golang-interfaces

Finalizando…

Aunque Golang no es un lenguaje de programación orientado a objetos, nos permite simular métodos y sobrecarga para facilitarnos un poco la abstracción de problemas propios de los lenguajes orientados a objetos. Además, si utilizamos métodos será más sencillo trabajar con un único identificador para realizar cierta operación similares; en este caso se pudo volver poco práctico crear una función dameAreaRectangulo() y una dameAreaTrapecio() puesto que necesitaríamos crear funciones con diferentes identificadores para cada figura nueva que pudiéramos agregar a nuestro programas; en su lugar los métodos nos permiten utilizar una sola función dameArea() o simplemente utilizar el registro para llamar a area().

Con esta entrada terminamos la primera parte de programación en Go básico, espero que todo te haya sido de utilidad. Hasta la próxima, see ya!

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *