Go é orientado a objetos ?
Tags: go
Published: 2020-08-25 01:44:30

Fala comigo galerinha, a semana começou agitada 😂, este post é sobre **Orientação** Objeto na linguagem de programação **Go**😍. É um assunto que tornou-se recorrente em listas de discussões, MeetUp, grupos etc. Quando o assunto é Programação Orientada a Objetos em **Go** causa uma polêmica.

Sabemos que a Linguagem **Go** é um **Like C** e também sabemos que a linguagem **Go** teve influências de diversas outras linguagens de programação e paradigmas diferentes, dentre elas: *Alef, APL, BCPL, C, CSP, Limbo, Modula, Newsqueak, Oberon, occam,Pascal, Smalltalk e Cristal*. Como podem perceber temos uma miscelânea de paradigmas porém o paradigma Imperativo e Concorrente são os que mais predominam em **Go**.

**Go** é uma linguagem orientada a objetos a resposta para esta pergunta é **SIM e NÃO** 😱. No site oficial Go em faq encontraremos alguns pontos sobre isto caso queira da uma conferida só clicar em: [Go Object Oriented Language](https://golang.org/doc/faq#Is_Go_an_object-oriented_language)

Em Go conseguimos desenvolver um estilo de programação orientada a objetos permitindo construir tipos e métodos porém não há hierarquia de tipos, é bem diferente da implementação que conhecemos em outras linguagens de programação porque não temos um arsenal de recursos como linguagens desenvolvidas para o paradigma orientadas a objetos. O que temos em **Go** é uma abstração para flexibilizar e ajudar quando precisarmos utilizar diferentes tipos de structs sem nos preocupar qual struct estará sendo utilizada e o mais legal deixa encapsulado seu método de forma segura.

Bem para que isto seja possível em Go temos um coadjuvante que se chama **“interface”** 💪🏼 ou seja **“type MyInterface interface{ ... }”** e sua abordagem como dissemos é diferente das implementações que conhecemos em outras langs, interface é a única forma de permitir o despacho de métodos dinâmicos em Go.

Então o que temos até o momento é uma forma de fazer **polimorfismo** utilizando **"interface"**, encapsulamento de métodos e disponibiliza-los de forma dinâmica tudo isto é muito semelhante ao **"Duck typing"**.

## O que é Duck typing

O Go suporta **“Duck typing”**, é um estilo de tipagem em que os métodos e propriedades de um objeto determinam a semântica válida, em vez de sua herança de uma classe particular ou implementação de uma interface explicita. O nome do conceito refere-se ao teste do pato, atribuído à *James Whitcomb Riley*. Isso faz com que o Go se pareça com uma linguagem dinâmica.

Go usa **"Tipagem Estrutural"** em métodos para determinar a compatibilidade de um tipo com uma interface. Não há hierarquias de tipos e a **“Tipagem Estrutural”** é uma alternativa interessante à herança clássica em linguagens com tipagem estática. 

Ele permite que você escreva algoritmos genéricos sem obscurecer a definição de um tipo em um mar de interfaces. Talvez mais importante, ajuda as linguagens com tipagem estática a capturar a sensação e a produtividade das linguagens dinamicamente tipificadas.

**"Duck typing"** ocorre em tempo de execução e **“Tipagem Estrutural”** que ocorre em tempo de compilação. Go não da suporte a orientação a objetos como é implementado nas linguagens como C#, Java ou mesmo C++, não possui herança e honestamente fico muito feliz com isto, mas oferece alguns recursos como composição e interfaces como descrevemos acima.

O exemplo abaixo demostra o comportamento do que seria **"Dunk typing"** apresentando um polimorfismo utilizando Go e composição utilizando structs e alguns tipos diferentes.

```go

package main

import (
    "fmt"
)

type Familia interface {
    Dados() string
}

type Pai struct {
    Nome  string
    Idade int
    Cpf   string `json:"cpf"`
}

func (p Pai) Dados() string {
    return fmt.Sprintf("Nome: %s, Idade: %d", p.Nome, p.Idade)
}

type Filho struct {
    Pai   Pai
    Idade int
    Nome  string
    Email string
}

func (f Filho) Dados() string {
    return fmt.Sprintf("\nNome: %s, Idade: %d, Email: %s", f.Nome, f.Idade, f.Email)
}

type Filhos []Filho

func (f Filhos) Dados() string {
    concat := ""
    for _, v := range f {
        concat += fmt.Sprintf("\nNome: %s, Idade: %d, Email: %s", v.Nome, v.Idade, v.Email)
    }
    return concat
}

func showDados(membro Familia) {

    fmt.Println(membro.Dados())
}

func showDados2(f []Familia) {
    for _, membro := range f {
        fmt.Println(membro.Dados())
    }
}

func main() {

    //// Pai
    pai := new(Pai)
    pai.Nome = "Jefferson"
    pai.Idade = 38
    pai.Cpf = "00.xxx.xxx-xx"

    var filho Filho
    var filhos Filhos

    //// Filhos
    filho.Pai.Nome = "Pai Nome Here"
    filho.Pai.Idade = 38
    filho.Pai.Cpf = "01.xxx.xxx-xx"

    filho.Nome = "Arthur"
    filho.Email = "arthur@gmail.com"
    filho.Idade = 4
    filhos = append(filhos, filho)

    filho.Nome = "Francisco"
    filho.Email = "francisco@gmail.com"
    filho.Idade = 7
    filhos = append(filhos, filho)

    //// Filha
    filha := new(Filho)
    filha.Nome = "Joyce"
    filha.Idade = 22
    filha.Email = "joycexxx@gmail.com"

    // Show Dados
    showDados(pai)

    showDados(filha)

    showDados(filhos)

    idadeFilhos := []Familia{pai, filha, filhos}
    showDados2(idadeFilhos)

}

```
Confira o exemplo completinho aqui: [executar o exemplo](https://play.golang.org/p/C3VbgbVQnhs﻿)

A interface é uma coleção de métodos, além de ser um tipo personalizado.

```go
type Familia interface {
   // Assinatura Função
}

type Familia interface {
    Dados() string
}

```
Dizemos que algo satisfaz esta interface (ou implementa esta interface ) se tiver um método com a assinatura exata Dados() string.

Por exemplo, a struct Pai satisfaz a interface porque tem um Dados() string definido como método.

```go

type Pai struct {
    Nome  string
    Idade int
    Cpf   string `json:"cpf"`
}

func (p Pai) Dados() string {
    return fmt.Sprintf("Nome: %s, Idade: %d", p.Nome, p.Idade)
}

```
Não é realmente importante o que esse “Pai” é ou faz. A única coisa que importa é que tem um método chamado Dados() que retorna uma string.

Ou, como Filhos, o tipo a seguir também satisfaz a **“interface Familia”** — novamente porque tem um método com a assinatura exata Dados() string.

```go
type Filho struct {
    Pai   Pai
    Idade int
    Nome  string
    Email string
}

func (f Filho) Dados() string {
    return fmt.Sprintf("\nNome: %s, Idade: %d, Email: %s", f.Nome, f.Idade, f.Email)
}

type Filhos []Filho

func (f Filhos) Dados() string {
    concat := ""
    for _, v := range f {
        concat += fmt.Sprintf("\nNome: %s, Idade: %d, Email: %s", v.Nome, v.Idade, v.Email)
    }
    return concat
}

```
O importante aqui é que temos três tipos diferentes Pai, Filho e Filhos, que fazem coisas diferentes. Mas o que eles têm em comum é que ambos satisfazem a “interface Familia”.

Podemos pensar sobre isto de outra maneira. Se você sabe que um objeto satisfaz a “interface Familia”, pode confiar que ele tem um método com a assinatura exata Dados() string que pode ser chamada.

Agora vamos conferir nossa função “showDados(…)” que será responsável por acessar todos nossos métodos diferentes atendendo a mesma interface, agora você poderá usar objetos de qualquer tipo desde que satisfaça a interface.

```go

func showDados(membro Familia) {
    fmt.Println(membro.Dados())
}

```
Olha o exemplo abaixo, temos vários tipos de objetos sendo passado para a função showDados(…).

```go
func main() {

    //// Pai
    pai := new(Pai)
    pai.Nome = "Jefferson"
    pai.Idade = 38
    pai.Cpf = "00.xxx.xxx-xx"

    var filho Filho
    var filhos Filhos

    //// Filhos
    filho.Pai.Nome = "Pai Nome Here"
    filho.Pai.Idade = 38
    filho.Pai.Cpf = "01.xxx.xxx-xx"

    filho.Nome = "Arthur"
    filho.Email = "arthur@gmail.com"
    filho.Idade = 4
    filhos = append(filhos, filho)

    filho.Nome = "Francisco"
    filho.Email = "francisco@gmail.com"
    filho.Idade = 7
    filhos = append(filhos, filho)

    //// Filha
    filha := new(Filho)
    filha.Nome = "Joyce"
    filha.Idade = 22
    filha.Email = "joycexxx@gmail.com"

    // Show Dados
    showDados(pai)

    showDados(filha)

    showDados(filhos)
}

```
As possibilidades são diversas, podemos definir uma interface recebendo outra interface, podemos criar outras funções que satisfaça a interface como o exemplo abaixo:

```go

idadeFilhos := []Familia{pai, filha, filhos}
showDados2(idadeFilhos)

```

A função showDados2(f []Familia) recebe um vetor da “interface Familia”.

```go

func showDados2(f []Familia) {
    for _, membro := range f {
        fmt.Println(membro.Dados())
    }
}

```

Simples não é ? Com esta definição temos diversas possibilidades que poderá utilizar “interface” em seus projetos. 

**Clean Architecture** é um bom exemplo desta utilização também, toda sua arquitetura se baseia-se em interfaces caso queiram da uma conferida alguns links legais [Clean Architecture using Golang](https://medium.com/@eminetto/clean-architecture-using-golang-b63587aa5e3f) e [Clean Architecture, 2 years later](https://eltonminetto.net/en/post/2020-07-06-clean-architecture-2years-later)

Existem alguns motivos pelos quais você poderia usar interface em Go, vou listar os três mais comuns:

. Para ajudar a reduzir a duplicação ou código padrão.

. Para tornar mais fácil usar mocks em vez de objetos reais em testes de unidade.

. Como uma ferramenta de arquitetura, para ajudar a impor o desacoplamento entre as partes de sua base de código.

## Algumas interfaces utilizada em Go em sua strand libray default

Uma pequena lista de algumas das interfaces mais comuns e úteis na biblioteca padrão.

1. builtin.Error
2. fmt.Stringer
3. io.Reader
4. io.Writer
5. io.ReadWriteCloser
6. http.ResponseWriter
7. http.Handler

## Aqui uma lista completa de interfaces em Go

[Lista completa](https://gist.github.com/asukakenji/ac8a05644a2e98f1d5ea8c299541fce9)

Caso queiram acessar o código fonte do exemplo apresentado e mais exemplos basta visitar este link.

[github.com/jeffotoni/goexample](https://github.com/jeffotoni/goexample)