Como trabalhar com herança em Go

Uma dúvida que tenho visto com certa frequência é sobre as classes e herança em Go.

Sempre lembrando que GO não tem orientação a objetos na sua forma original de ser. Porém, quando o assunto é classe e herança, é possível alcançar algo similar utilizando structs e a técnica de embedding.

Tento esclarecido isso, vamos ver como podemos utilizar “herança” em Go imaginando um banco de dados com 4 tabelas.

imagem meramente ilustrativa 😉

Agora vamos escrever as structs que representam cada uma dessas tabelas, sem se preocupar com a relação entre elas ainda.

type Pessoa struct {
    Nome           string
    Documento      string
    DataNascimento time.Time
}

type PessoaJuridica struct {
    InscricaoEstadual string
}

type PessoaFisica struct {
    Sobrenome string
    RG        string
}

type Endereco struct {
    Tipo     string
    Endereco string
    Bairro   string
    Cidade   string
    Estado   string
}

Como a tabela pessoa tem uma relação de 1:1 com as tabelas pessoa_juridica e pessoa_fisica, ou seja, uma relação de herança, vamos deixar para trabalhar nelas depois. Antes, vamos focar na relação de pessoa e endereco, pois essa relação será refletida na relação de herança.

A nossa tabela pessoa tem uma relação de 1:N com a tabela endereco, ou seja, para cada registro na tabela pessoa, eu posso ter N registros na tabela endereco.

E como N nada mais é do que um array, para trazer essa representação à nossa struct, vamos fazer a seguinte modificação.

type Pessoa struct {
    Nome           string
    Documento      string
    DataNascimento time.Time
    Enderecos      []Endereco // campo adicionado
}

Agora, para trazer a representação de 1:1 às nossas structs, vamos utilizar uma técnica chamada de embedding.

Essa técnica consiste em referenciar uma struct dentro de outra sem criar um atributo para isso.

No nosso caso, essa mudança deixará nossas structs PessoaJuridica e PessoaFisica da seguinte forma.

type PessoaJuridica struct {
    Pessoa // embedding
    InscricaoEstadual string
}

type PessoaFisica struct {
    Pessoa // embedding
    Sobrenome string
    RG        string
}

Utilizando essa técnica, conseguimos utilizar os atributos e métodos da struct Pessoa de forma direta, sem ter que chamar um .Pessoa antes.

// sem embedding
fmt.Println(pj.Pessoa.Nome)

// com embedding
fmt.Println(pj.Nome)

Agora que temos todas as relações feitas, vamos adicionar três métodos.

O primeiro método vai retornar a idade da Pessoa.

func (p *Pessoa) Idade() int {
    return time.Now().Year() - p.DataNascimento.Year()
}

O segundo método vai retornar o nome completo da PessoaFisica.

func (pf *PessoaFisica) NomeCompleto() string {
    return fmt.Sprintf("%s %s", pf.Nome, pf.Sobrenome)
}

E o terceiro vai retornar o Endereco formatado.

func (e *Endereco) Completo() string {
    return fmt.Sprintf("%s: %s, %s, %s - %s", e.Tipo, e.Endereco, e.Bairro, e.Cidade, e.Estado)
}

Em um programinha bem simples, vamos iniciar uma struct do tipo PessoaFisica e depois executar esses três métodos que criamos.

func main() {
    pf := PessoaFisica{
        Pessoa{
            Nome:           "Tiago",
            Documento:      "000.000.000-00",
            DataNascimento: time.Date(1990, 02, 22, 7, 0, 0, 0, time.Local),
            Enderecos: []Endereco{
                {
                    Tipo:     "casa",
                    Endereco: "Rua dos Gophers",
                    Bairro:   "Imperial",
                    Cidade:   "GoCity",
                    Estado:   "GOstate",
                },
             },
         },
         "Temporin",
         "00.000.000-00",
    }

    fmt.Println("Nome:", pf.NomeCompleto())
    fmt.Println("Idade:", pf.Idade())
    for _, e := range pf.Enderecos {
        fmt.Println("Endereço:", e.Completo())
    }
}

Como podemos ver, utilizando a técnica de embedding para tratar relações de herança ajuda muito, pois todas as structs vão herdar seus atributos, métodos e relações.

Espero que tenha ajudado!

Se ficou alguma dúvida, deixa um comentário aí que eu respondo assim que possível.

Obrigado e até a próxima!


Se inscreva na nossa newsletter

* indicates required

Deixe uma resposta