Pular para o conteúdo principal

victorstein.dev

86/100 Dias de Golang - Conceitos de POO

Table of Contents

# Conceitos de POO

Como vimos em outros posts, Go não é uma linguagem orientada a objetos. Mas com os recursos disponibilizados pela linguagem, podemos implementar os conceitos de POO.

# Structs em vez de classes

Em linguagens como Java, C++ ou Python, a orientação a objetos gira em torno de classes e objetos. Em Go, não existem classes. Em vez disso, usamos structs, que são tipos compostos. Vamos criar uma struct para representar uma carta de baralho:

type Carta struct {
	Naipe string
	Rank  string
}

Temos que Naipe e Rank são os atributos da nossa “classe” Carta

# Métodos

Go permite associar funções a structs — o que se assemelha aos métodos de uma classe na POO tradicional.

func (c Carta) Exibir() {
	fmt.Println("Naipe: ", c.Naipe, " Rank: ", c.Rank)
}

Podemos criar uma instância de Carta e chamar o método Exibir

c := Carta{Naipe: "espada", Rank: "8"}
c.Exibir()

# Encapsulamento: Exportado ou não-exportado

Go não possui private, protected ou public como Java. Mas o encapsulamento existe de forma mais simples. O controle de visibilidade (encapsulamento) é baseado na capitalização do identificador. Letra maiúscula → público (exportado), letra minúscula → privado (não exportado).

type Pessoa struct {
    Nome  string // Público - primeira letra maiúscula
    Idade int    // Público
    cpf   string // Privado - primeira letra minúscula
    senha string // Privado
}

# Herança

Go não possui herança tradicional, mas isso não significa que você não possa reutilizar código. Em vez disso usamos a composição

type Endereco struct {
    Cidade string
}

func (e Endereco) VerificaCidade() bool {
	return e.Cidade != ""
}

type Pessoa struct {
    Nome string
    Endereco
}

Com isso, Pessoa passa a ter acesso direto aos campos e métodos de Endereco:

p := Pessoa{Nome: "Victor", Endereco: Endereco{Cidade: "Curitiba"}}
cidadeValida := p.VerificaCidade()

fmt.Println("Cidade válida? :", cidadeValida)

## Interfaces e Polimorfismo

Um ponto muito interessante de Go são suas interfaces implícitas. Diferente de Java ou C#, em Go você não precisa declarar que uma struct implementa uma interface. Se ela atende aos métodos da interface, ela a implementa. Nesse exemplo temos duas structs BaralhoFrances e BaralhoEspanhol e ambas implementam o método Embaralhar da interface Baralho

type Baralho interface {
	Embaralhar()
}

type BaralhoFrances struct {
	Nome string
}

type BaralhoEspanhol struct {
	Nome string
}

func (bf BaralhoFrances) Embaralhar() {
	fmt.Println("Embaralhando Baralho", bf.Nome)

}

func (be BaralhoEspanhol) Embaralhar() {
	fmt.Println("Embaralhando Baralho", be.Nome)
}

Logo, se criarmos uma função GetBaralhoEmbaralhado que recebe um parâmetro (b Baralho), poderei passar tanto uma instância de BaralhoFrances quanto de BaralhoEspanhol.

func GetBaralhoEmbaralhado(b Baralho) {
	b.Embaralhar()
}

bf := BaralhoFrances{Nome: "Francês"}
be := BaralhoEspanhol{Nome: "Espanhol"}

GetBaralhoEmbaralhado(bf)
GetBaralhoEmbaralhado(be)

Note que GetBaralhoEmbaralhado recebe como parâmetro a interface Baralho. Como BaralhoFrances e BaralhoEspanhol implementam essa interface, podemos passar instâncias de ambas para essa função sem necessidade de declaração explícita.

Mesmo sem aderir completamente ao paradigma orientado a objetos, Go permite aplicar diversos de seus conceitos de forma idiomática. Composição, interfaces implícitas e encapsulamento por convenção tornam o código mais simples e direto, mantendo os princípios de legibilidade e eficiência que caracterizam a linguagem.

# Referências: