En Go no existe un concepto como la herencia que nos permita reutilizar métodos y propiedades de otras clases, tampoco cuenta con clases abstractas comunes en lenguajes como C#, en su lugar Go ofrece la capacidad de embeber tipos dentro de otros tipos, podemos utilizar esta característica con las siguientes combinaciones: estructuras dentro de estructuras, interfaces dentro de interfaces o interfaces dentro de estructuras. En este post voy a describir los dos más comunes con pequeños ejemplos.

Embebiendo estructuras dentro de estructuras

Dentro de nuestro código podemos tener la necesidad de utilizar las mismas propiedades para diferentes estructuras como se muestra en el siguiente ejemplo, como podrás notar se duplican las propiedades firstName y lastName.

type Person struct {
	ID        uint
	firstName string
	lastName  string
}

type Employee struct {
	ID        uint
	firstName string
	lastName  string
}

En esos casos podemos utilizar la estructura Person como un campo para evitar código repetido tal como lo muestra el siguiente código:

type Person struct {
	ID        uint
	firstName string
	lastName  string
}

type Employee struct {
	person Person
}

El código anterior tendría que ser utilizado de la siguiente manera dentro de nuestro programa.

func (e *Employee) FullName() string {
	return fmt.Printf("firstName: %v lastName: %v",
		e.person.firstName,
		e.person.lastName)
}

Este enfoque no será simple de utilizar ya que por cada tipo terminaríamos navegando en cada uno de sus campos o propiedades, afortunadamente en Go podemos simplificar esto utilizando composition con tipos embebidos, para ello tendremos que realizar un pequeño cambio en nuestro código tal como se muestra a continuación.

type Employee struct {
	Person
}

Lo cuál nos permitiría simplificar nuestro método FullName ya que podemos utilizar los campos como si le pertenecieran a nuestra estructura Employee.

func (e *Employee) FullName() string {
	return fmt.Printf("firstName: %v lastName: %v",
		e.firstName,
		e.lastName)
}

Embebiendo interfaces dentro de interfaces

Al igual que con las estructuras podemos hacer uso de composition con tipos embebidos en las interfaces, un ejemplo sencillo es el siguiente en el que tenemos dos interfaces Reader y Writer con el siguiente código.

type Reader interface {
	Read(id uint) (model.Person, error)
}

type Writer interface {
	Write(p model.Person) error
}

Ahora podemos embeberlas dentro de otra interfaz llamada Repository como se muestra en el siguiente código.

type Repository interface {
	Reader
	Writer
}

Lo que nos va a permitir implementar los métodos de ambas interfaces en una estructura como muestra el siguiente ejemplo.

type PeopleRepository struct {
	people map[uint]model.Person
}

var _ Repository = &PeopleRepository{}

func NewRepository() PeopleRepository {
	return PeopleRepository{
		people: make(map[uint]model.Person),
	}
}

func (repo *PeopleRepository) Read(id uint) (model.Person, error) {
	p, found := repo.people[id]
	if !found {
		return model.Person{}, fmt.Errorf("not found person for id: %d", id)
	}
	return p, nil
}

func (repo *PeopleRepository) Write(p model.Person) error {
	repo.people[p.ID] = p
	return nil
}

Esta característica de embeber tipos me parece muy sencilla de aprender y utilizar, lo que nos permitirá reutiliza código dentro de nuestras aplicaciones escritas en Go.

Happy coding!
@SaturPimentel

Imagen obtenida de unsplash