Go é Orientada a Objetos? A resposta pragmática para uma dúvida comum

Posted on Feb 21, 2026
cloud-native

golang/go

Introdução

Se você perguntar para três desenvolvedores se Go é uma linguagem Orientada a Objetos (OO), você provavelmente receberá quatro respostas diferentes. Uns dirão que é procedural “com esteroides”, outros que é funcional por causa das funções de primeira classe, e alguns defenderão que é OO purista.

Sempre gosto de dizer que a melhor linguagem é que resolverá o seu problema da melhor forma.

A verdade? Go é o que você precisa que ela seja, mas ela odeia burocracia (isso que me fez amar desde cedo).

Mas a realidade é mais sofisticada. Segundo o FAQ oficial do Go: “Sim e não”. Go é OO, mas não da forma que você aprendeu na faculdade. Vamos entender os pilares da OO sob a ótica de um Gopher.

O que Go NÃO tem (e por que isso confunde)

Para quem vem do Java ou C#, a falta de certos pilares pode parecer estranha:

  • Não existem classes: Temos structs;
  • Não existe herança: Você não pode fazer uma struct Dog extends Animal;
  • Não existe polimorfismo de subtipo: Esqueça as hierarquias complexas.

O que Go TEM (A alma da OO)

Se definirmos OO como “objetos que encapsulam estado e expõem comportamento”, Go é absolutamente OO:

  • Encapsulamento: Usamos maiúsculas e minúsculas para exportar (ou não) campos e funções;
  • Métodos: Você pode pendurar métodos em qualquer tipo, não só em structs;
  • Interfaces (O superpoder): Em Go, as interfaces são satisfeitas implicitamente. Se algo “caminha como um pato”, ele é um pato. Não precisa de implements.

O veredito: Composição sobre Herança

Tenho um artigo antigo onde explico a diferença entre Herança e Composição.

Sobre o Veredito: Go é Orientada a Objetos?

Se você define OO como hierarquias de classes e herança de tipos, então não. Mas, se você define OO como um paradigma que permite:

  • Encapsular estado;
  • Definir comportamento (métodos) para tipos;
  • Usar polimorfismo (interfaces).

Então Go é uma das linguagens OO mais pragmáticas e eficientes que existem. Ela remove a “cerimônia” e foca na composição, o que evita o famoso problema da “fronteira frágil” em sistemas grandes.

Go força você a usar composição. Em vez de dizer que um Gerente é um Funcionario, em Go dizemos que um Gerente contém um Funcionario. É uma mudança de mindset que gera códigos mais flexíveis e fáceis de testar.

Exemplos

1. Encapsulamento: O poder das iniciais

Em linguagens tradicionais, usamos public, private e protected. Em Go, o encapsulamento é resolvido no nível do package através da capitalização.

  • Inicia com Maiúscula: Exportado (Público);
  • Inicia com Minúscula: Não exportado (Privado ao package).
package account

type CheckingAccount struct {
  Owner  string  // Público
  balance float64 // Privado: ninguém fora do package 'account' altera o saldo direto
}

// NewCheckingAccount é o nosso "Construtor"
func NewCheckingAccount(owner string) *CheckingAccount {
  return &CheckingAccount{Owner: owner, balance: 0}
}

// Deposit é um método (comportamento)
func (c *CheckingAccount) Deposit(amount float64) {
  if amount > 0 {
    c.balance += amount
  }
}

2. Métodos em qualquer lugar

Diferente do Java, onde métodos pertencem a classes, em Go você pode adicionar comportamento a qualquer tipo definido no seu package. Isso é OO puro: associar dado ao comportamento.

type Celsius float64

// Adicionando comportamento a um tipo primitivo (float64)
func (c Celsius) IsFreezing() bool {
  return c <= 0
}

func main() {
  temp := Celsius(25.5)
  fmt.Println(temp.IsFreezing()) // false
}

3. Adeus Herança, Olá Composição

Este é o ponto onde muitos desenvolvedores “travam”. Go não permite que uma struct herde campos e métodos de outra. Em vez disso, usamos Struct Embedding (composição).

Em vez de dizer que um Gerente é um Funcionario, dizemos que um Gerente contém um Funcionario.

type User struct {
  Name  string
  Email string
}

func (u User) Label() string {
  return fmt.Sprintf("%s (%s)", u.Name, u.Email)
}

type Admin struct {
  User  // Embedding: Admin "ganha" os campos e métodos de User
  Level int
}

func main() {
  a := Admin{
      User:  User{Name: "Alice", Email: "alice@dev.com"},
      Level: 1,
  }
  
  // Podemos acessar Label() direto em 'a' como se fosse dele
  fmt.Println(a.Label()) 
}

4.Interfaces: O Polimorfismo Implícito

O maior trunfo do Go é a interface. Em C#, você precisa declarar class Pato: IPato. Em Go, se a sua struct tem os métodos que uma interface pede, ela automaticamente satisfaz a interface.

Isso é chamado de Structural Typing (ou Duck Typing estático).

type Speaker interface {
    Speak() string
}

type Dog struct{}
type Robot struct{}

func (d Dog) Speak() string { 
  return "Au Au!" 
}

func (r Robot) Speak() string {
  return "Beep Boop!" 
}

// Esta função não sabe (nem se importa) o que é um Dog ou Robot
func MakeItSpeak(s Speaker) {
  fmt.Println(s.Speak())
}

O que vem a seguir?

Agora que entendemos que Go favorece a composição e o desacoplamento, como aplicamos regras rígidas de design para manter esse código limpo? No próximo artigo, vamos explorar o Object Calisthenics aplicado ao Go.

Mas, você já pode dar uma lida sobre, neste artigo do mestre Elton Minetto sobre o assunto: Como melhorar seus códigos usando Object Calisthenics

Conclusão

Go é uma linguagem multiparadigma que abraça a simplicidade. Ela pega o melhor da OO (interfaces e encapsulamento) e joga fora o pior (hierarquias de herança profundas).