0Pricing
Go Academy · Aula

Composição de interfaces e boas práticas

Interfaces pequenas e inversão de dependências

Composição de interfaces e boas práticas é uma aula grátis de Go Academy no CoddyKit. Esta é a aula 4 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de Go Academy, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de Go Academy inclui 4 aulas no total.

Composição de interfaces

As interfaces de Go podem incorporar outras interfaces para compor interfaces maiores:

package main
import "io"

// io.ReadWriter composes Reader and Writer
type ReadWriter interface {
    io.Reader
    io.Writer
}

// Your own composition:
type Processor interface {
    io.Reader
    Process() error
    io.Closer
}

func main() { _ = (*Processor)(nil) }

Princípio das interfaces pequenas

As interfaces mais poderosas de Go têm um ou dois métodos. Isso maximiza o número de tipos que podem satisfazê-las:

  • io.Reader — 1 método
  • io.Writer — 1 método
  • error — 1 método
  • fmt.Stringer — 1 método

Interfaces grandes são mais difíceis de simular e testar.

Inversão de dependência

Aceite interfaces nos parâmetros das funções em vez de tipos concretos. Isso desacopla seu código de implementações específicas:

package main
import "fmt"

type Store interface {
    Get(key string) (string, bool)
    Set(key, val string)
}

func cache(s Store, key, value string) {
    if _, ok := s.Get(key); !ok {
        s.Set(key, value)
    }
}

type MapStore struct{ m map[string]string }
func (ms *MapStore) Get(k string) (string, bool) { v, ok := ms.m[k]; return v, ok }
func (ms *MapStore) Set(k, v string) { ms.m[k] = v }

func main() {
    s := &MapStore{m: map[string]string{}}
    cache(s, "x", "hello")
    v, _ := s.Get("x")
    fmt.Println(v)
}

Segregação de interfaces

Divida interfaces grandes em interfaces menores e focadas. Os clientes dependem apenas dos métodos que usam:

package main

// Bad: large interface forces all methods
type BigStorage interface {
    Read(key string) string
    Write(key, val string)
    Delete(key string)
    List() []string
    Backup() error
}

// Good: small, focused interfaces
type Reader interface{ Read(key string) string }
type Writer interface{ Write(key, val string) }
type Lister interface{ List() []string }

func readAll(r Reader) {} // only needs Read

func main() { _ = readAll }

Retorno de tipos concretos

Os construtores devem retornar tipos concretos, não interfaces. Os chamadores sempre podem atribuir um tipo concreto a uma variável de interface:

package main

type Logger interface{ Log(string) }
type ConsoleLogger struct{}
func (c *ConsoleLogger) Log(s string) {}

// Good: return concrete *ConsoleLogger
func NewConsoleLogger() *ConsoleLogger { return &ConsoleLogger{} }

// Avoid: return Logger (hides the concrete type)
// func NewConsoleLogger() Logger { return &ConsoleLogger{} }

func main() { _ = NewConsoleLogger() }

Poluição de interfaces

Não crie uma interface para cada tipo "por precaução". Crie interfaces somente quando:

  • Você tem várias implementações agora ou em breve
  • Precisa simular a dependência nos testes
  • Está criando uma biblioteca e quer desacoplar os chamadores

Incorporação de interfaces para extensão

Incorpore uma interface para adicionar métodos opcionais com implementações padrão:

package main
import "fmt"

type Handler interface{ Handle(msg string) }
type NamedHandler interface {
    Handler
    Name() string
}

func dispatch(h Handler) {
    if nh, ok := h.(NamedHandler); ok {
        fmt.Printf("[%s] ", nh.Name())
    }
    h.Handle("event")
}

type MyHandler struct{}
func (m MyHandler) Handle(msg string)  { fmt.Println(msg) }
func (m MyHandler) Name() string       { return "my" }

func main() { dispatch(MyHandler{}) }

Simulação com interfaces

Defina as dependências como interfaces; injete simulações nos testes:

package main
import "fmt"

type Clock interface{ Now() int64 }

type MockClock struct{ T int64 }
func (m MockClock) Now() int64 { return m.T }

func isExpired(c Clock, expiresAt int64) bool {
    return c.Now() > expiresAt
}

func main() {
    mc := MockClock{T: 1000}
    fmt.Println(isExpired(mc, 500))  // true
    fmt.Println(isExpired(mc, 1500)) // false
}

Incorporação de interfaces versus estruturas para reutilização

Use a incorporação de interfaces para compor APIs e a incorporação de estruturas para reutilizar código. Elas têm finalidades diferentes e não devem ser confundidas.

Detecção da conformidade com interfaces em tempo de compilação

Use uma verificação em tempo de compilação com um identificador em branco para confirmar que seu tipo satisfaz uma interface:

package main

type Doer interface{ Do() }
type MyType struct{}
func (m *MyType) Do() {}

// Compile-time check — no runtime cost
var _ Doer = (*MyType)(nil)

func main() {}

Verificação rápida

Quando você deve definir uma nova interface em Go?

Recapitulação: práticas recomendadas para interfaces

Principais conclusões:

  • Mantenha as interfaces pequenas — um ou dois métodos
  • Componha interfaces a partir de interfaces menores
  • Aceite interfaces e retorne tipos concretos
  • Crie interfaces para facilitar os testes e permitir várias implementações
  • Use uma verificação em tempo de compilação por atribuição a um identificador em branco

Proposta de prática

Projete uma interface Notifier com Notify(msg string) error. Implemente-a para EmailNotifier e SMSNotifier. Escreva uma função broadcast que envie para um []Notifier.

Perguntas Frequentes

A aula “Composição de interfaces e boas práticas” é grátis?

Sim — o texto completo de “Composição de interfaces e boas práticas” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de Go Academy, atualize para CoddyKit PRO. O curso de Go Academy inclui 4 aulas no total.

O que vou aprender em “Composição de interfaces e boas práticas”?

Interfaces pequenas e inversão de dependências Você pratica Go Academy com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.

Preciso ter experiência prévia para começar Go Academy?

Nenhuma experiência prévia é necessária. Go Academy no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 4 de 4.

Quanto tempo leva a aula “Composição de interfaces e boas práticas”?

A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.

Posso escrever e executar código nesta aula de Go Academy?

Sim. Cada aula de Go Academy inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.

Todas as aulas deste curso

  1. Definindo e implementando interfaces
  2. Interfaces essenciais da biblioteca padrão
  3. Asserções de tipo e switches de tipo
  4. Composição de interfaces e boas práticas
← Voltar para Go Academy