Patterns
Padrões de design mais utilizados em Go.
1. Error Handling Pattern
Go não usa exceções. O idioma é retornar erros como valores:
func divide(a, b float64) (float64, error) {
if b == 0 {
return 0, fmt.Errorf("divisão por zero")
}
return a / b, nil
}
// Uso
result, err := divide(10, 0)
if err != nil {
log.Fatal(err)
}
fmt.Println(result)2. Worker Pool Pattern
Padrão para processar tarefas concorrentemente com um número limitado de workers:
func worker(id int, jobs <-chan int, results chan<- int) {
for j := range jobs {
fmt.Printf("Worker %d processando job %d\n", id, j)
time.Sleep(time.Second)
results <- j * 2
}
}
func main() {
jobs := make(chan int, 100)
results := make(chan int, 100)
// Inicia 3 workers
for w := 1; w <= 3; w++ {
go worker(w, jobs, results)
}
// Envia 5 jobs
for j := 1; j <= 5; j++ {
jobs <- j
}
close(jobs)
// Coleta resultados
for a := 1; a <= 5; a++ {
<-results
}
}3. Singleton Pattern
Garantir que uma struct tenha apenas uma instância:
package main
import "sync"
type singleton struct {
count int
}
var instance *singleton
var once sync.Once
func GetInstance() *singleton {
once.Do(func() {
instance = &singleton{}
})
return instance
}4. Factory Pattern
Criar objetos sem especificar a classe exata:
type Animal interface {
Speak() string
}
type Dog struct{}
func (d Dog) Speak() string { return "Woof!" }
type Cat struct{}
func (c Cat) Speak() string { return "Meow!" }
func NewAnimal(animalType string) Animal {
switch animalType {
case "dog":
return Dog{}
case "cat":
return Cat{}
default:
return nil
}
}
// Uso
animal := NewAnimal("dog")
fmt.Println(animal.Speak()) // Woof!5. Options Pattern
Padrão para configurações flexíveis de structs:
type Server struct {
host string
port int
timeout time.Duration
}
type Option func(*Server)
func WithHost(host string) Option {
return func(s *Server) {
s.host = host
}
}
func WithPort(port int) Option {
return func(s *Server) {
s.port = port
}
}
func NewServer(opts ...Option) *Server {
s := &Server{
host: "localhost",
port: 8080,
timeout: 30 * time.Second,
}
for _, opt := range opts {
opt(s)
}
return s
}
// Uso
server := NewServer(
WithHost("0.0.0.0"),
WithPort(3000),
)6. Context Pattern
Para cancelamento e timeout de operações:
func longRunningTask(ctx context.Context) error {
for {
select {
case <-ctx.Done():
return ctx.Err() // Cancelado ou timeout
default:
// Faz o trabalho
time.Sleep(100 * time.Millisecond)
}
}
}
// Uso
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
if err := longRunningTask(ctx); err != nil {
log.Println("Erro:", err)
}7. Interface Segregation
Interfaces pequenas e específicas:
// Ruim - interface muito grande
type Animal interface {
Eat()
Sleep()
Fly()
Swim()
}
// Bom - interfaces segregadas
type Eater interface {
Eat()
}
type Sleeper interface {
Sleep()
}
type Flyer interface {
Fly()
}
type Bird struct{}
func (b Bird) Eat() {}
func (b Bird) Sleep() {}
func (b Bird) Fly() {}8. Defer Pattern
Garantir limpeza de recursos:
func readFile(filename string) error {
file, err := os.Open(filename)
if err != nil {
return err
}
defer file.Close() // Sempre fecha o arquivo
// Processa o arquivo
scanner := bufio.NewScanner(file)
for scanner.Scan() {
fmt.Println(scanner.Text())
}
return scanner.Err()
}