Princípios SOLID em Go: guia avançado com exemplos

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

Princípios SOLID em Go: nível avançado



SOLID são cinco princípios fundamentais de design orientado a objetos que ajudam a criar código flexível, sustentável e escalável. No contexto do Go, uma linguagem com a filosofia única de composição em vez de herança, a aplicação do SOLID requer uma abordagem especial. Neste artigo, analisaremos cada princípio em nível avançado, com exemplos reais e antipadrões característicos da comunidade Go.



1. Single Responsibility Principle (SRP) em Go



Princípio da responsabilidade única afirma: uma classe (struct) deve ter apenas um motivo para mudar. Em Go, isso é frequentemente violado em pacotes utilitários e "objetos divinos".



Antipadrão: struct com múltiplas responsabilidades



type UserService struct {    db *sql.DB    cache *redis.Client    logger *log.Logger}

func (s *UserService) CreateUser(ctx context.Context, u User) error { // 1. Validação // 2. Hash de senha // 3. Salvar no BD // 4. Enviar email // 5. Log return nil}


Solução: divida as responsabilidades em serviços separados e use composição.



type UserValidator interface {    Validate(u User) error}

type PasswordHasher interface { Hash(password string) (string, error)}

type UserRepository interface { Save(ctx context.Context, u User) error}

type EmailSender interface { SendWelcomeEmail(ctx context.Context, email string) error}

type UserService struct { validator UserValidator hasher PasswordHasher repo UserRepository emailSender EmailSender logger Logger}


Cada componente agora tem um motivo para mudar, simplificando testes e manutenção.



2. Open-Closed Principle (OCP) através de interfaces



Princípio aberto/fechado: entidades devem estar abertas para extensão, mas fechadas para modificação. Em Go, isso é alcançado através de interfaces e injeção de dependências.



Exemplo ruim: acoplamento rígido



type PaymentProcessor struct {    paypalAPI *PayPalAPI}

func (p *PaymentProcessor) Process(amount float64) error { return p.paypalAPI.Charge(amount)}


Se precisar adicionar Stripe — terá que alterar o código.



Abordagem correta: interface + estratégia



type PaymentGateway interface {    Charge(amount float64) error    Refund(transactionID string) error}

type PayPalGateway struct{ /* ... */ }type StripeGateway struct{ /* ... */ }

func (p *PayPalGateway) Charge(amount float64) error { /* ... */ }func (s *StripeGateway) Charge(amount float64) error { /* ... */ }

type PaymentService struct { gateway PaymentGateway}

func NewPaymentService(gw PaymentGateway) *PaymentService { return &PaymentService{gateway: gw}}


Agora é possível adicionar novos gateways de pagamento sem alterar o PaymentService.



3. Liskov Substitution Principle (LSP) no contexto do Go



Princípio da substituição de Barbara Liskov: objetos em um programa devem ser substituíveis por instâncias de seus subtipos sem alterar a correção do programa. Em Go, onde não há herança clássica, o LSP se manifesta através de contratos de interfaces.



Violação típica: interface com métodos redundantes



type Bird interface {    Fly() error    Swim() error}

type Penguin struct{}

func (p *Penguin) Fly() error { return errors.New("penguins can't fly")}

func (p *Penguin) Swim() error { return nil}


Aqui, Penguin não pode implementar corretamente Fly(), violando o LSP.



Solução: separação de interfaces



type Flyer interface {    Fly() error}

type Swimmer interface { S

Blogs

Book Recommendations