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()
}