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.