Skip to content

Instantly share code, notes, and snippets.

@williamkoller
Created May 27, 2025 12:23
Show Gist options
  • Save williamkoller/2aff1c9406528e32fde23383bbb39d60 to your computer and use it in GitHub Desktop.
Save williamkoller/2aff1c9406528e32fde23383bbb39d60 to your computer and use it in GitHub Desktop.
SOLID em go
package main
import (
"fmt"
"strings"
"time"
)
// ============================================================================
// 1. SINGLE RESPONSIBILITY PRINCIPLE (SRP)
// ============================================================================
// ❌ EXEMPLO RUIM: Uma struct fazendo muitas coisas
type BadUserManager struct {
Name string
Email string
Password string
}
// Mistura validação, persistência, notificação e criptografia
func (u *BadUserManager) CreateUser() error {
// Validação
if len(u.Name) < 2 {
return fmt.Errorf("nome muito curto")
}
if !strings.Contains(u.Email, "@") {
return fmt.Errorf("email inválido")
}
// Criptografia
u.Password = "hash_" + u.Password
// Persistência (simulada)
fmt.Printf("Conectando ao banco de dados...\n")
fmt.Printf("INSERT INTO users VALUES ('%s', '%s', '%s')\n", u.Name, u.Email, u.Password)
// Notificação por email
fmt.Printf("Conectando ao servidor SMTP...\n")
fmt.Printf("Enviando email de boas-vindas para %s\n", u.Email)
// Log
fmt.Printf("[%s] Usuário %s criado\n", time.Now().Format("15:04:05"), u.Name)
return nil
}
// ✅ EXEMPLO BOM: Responsabilidades separadas
type User struct {
Name string
Email string
Password string
}
type UserValidator struct{}
func (v *UserValidator) Validate(user User) error {
if len(user.Name) < 2 {
return fmt.Errorf("nome muito curto")
}
if !strings.Contains(user.Email, "@") {
return fmt.Errorf("email inválido")
}
return nil
}
type PasswordHasher struct{}
func (h *PasswordHasher) Hash(password string) string {
return "hash_" + password
}
type UserRepository struct{}
func (r *UserRepository) Save(user User) error {
fmt.Printf("Conectando ao banco de dados...\n")
fmt.Printf("INSERT INTO users VALUES ('%s', '%s', '%s')\n", user.Name, user.Email, user.Password)
return nil
}
type EmailService struct{}
func (e *EmailService) SendWelcome(email string) error {
fmt.Printf("Conectando ao servidor SMTP...\n")
fmt.Printf("Enviando email de boas-vindas para %s\n", email)
return nil
}
type Logger struct{}
func (l *Logger) Log(message string) {
fmt.Printf("[%s] %s\n", time.Now().Format("15:04:05"), message)
}
// Coordenador que usa as responsabilidades separadas
type GoodUserService struct {
validator *UserValidator
hasher *PasswordHasher
repository *UserRepository
email *EmailService
logger *Logger
}
func (s *GoodUserService) CreateUser(name, email, password string) error {
user := User{Name: name, Email: email, Password: password}
if err := s.validator.Validate(user); err != nil {
return err
}
user.Password = s.hasher.Hash(password)
if err := s.repository.Save(user); err != nil {
return err
}
s.email.SendWelcome(user.Email)
s.logger.Log(fmt.Sprintf("Usuário %s criado", user.Name))
return nil
}
// ============================================================================
// 2. OPEN/CLOSED PRINCIPLE (OCP)
// ============================================================================
// ❌ EXEMPLO RUIM: Modificação necessária para novos tipos
type BadDiscountCalculator struct{}
func (d *BadDiscountCalculator) CalculateDiscount(customerType string, amount float64) float64 {
switch customerType {
case "regular":
return amount * 0.05
case "vip":
return amount * 0.10
case "premium":
return amount * 0.15
// Para adicionar "student", preciso MODIFICAR esta função!
case "student":
return amount * 0.20
default:
return 0
}
}
// ✅ EXEMPLO BOM: Extensível sem modificação
type DiscountStrategy interface {
Calculate(amount float64) float64
Description() string
}
type RegularCustomerDiscount struct{}
func (r RegularCustomerDiscount) Calculate(amount float64) float64 {
return amount * 0.05
}
func (r RegularCustomerDiscount) Description() string {
return "5% desconto cliente regular"
}
type VIPCustomerDiscount struct{}
func (v VIPCustomerDiscount) Calculate(amount float64) float64 {
return amount * 0.10
}
func (v VIPCustomerDiscount) Description() string {
return "10% desconto cliente VIP"
}
type PremiumCustomerDiscount struct{}
func (p PremiumCustomerDiscount) Calculate(amount float64) float64 {
return amount * 0.15
}
func (p PremiumCustomerDiscount) Description() string {
return "15% desconto cliente Premium"
}
// NOVA funcionalidade adicionada SEM modificar código existente
type StudentDiscount struct{}
func (s StudentDiscount) Calculate(amount float64) float64 {
return amount * 0.20
}
func (s StudentDiscount) Description() string {
return "20% desconto estudante"
}
type GoodDiscountCalculator struct{}
func (d *GoodDiscountCalculator) ProcessOrder(amount float64, strategy DiscountStrategy) (float64, string) {
discount := strategy.Calculate(amount)
return amount - discount, strategy.Description()
}
// ============================================================================
// 3. LISKOV SUBSTITUTION PRINCIPLE (LSP)
// ============================================================================
// ❌ EXEMPLO RUIM: Subtipos que quebram o comportamento esperado
type BadBird interface {
Fly() string
}
type BadEagle struct{}
func (e BadEagle) Fly() string {
return "Águia voando alto"
}
type BadPenguin struct{}
func (p BadPenguin) Fly() string {
// VIOLA LSP: Pinguim não pode voar, mas a interface exige
panic("Pinguins não podem voar!")
}
// Função que falha com alguns tipos de BadBird
func MakeBadBirdFly(bird BadBird) {
fmt.Println(bird.Fly()) // Vai dar panic com Penguin!
}
// ✅ EXEMPLO BOM: Hierarquia que respeita LSP
type Bird interface {
Eat() string
Move() string
}
type FlyingBird interface {
Bird
Fly() string
}
type SwimmingBird interface {
Bird
Swim() string
}
type Eagle struct{}
func (e Eagle) Eat() string {
return "Águia caçando peixes"
}
func (e Eagle) Move() string {
return "Águia se movendo"
}
func (e Eagle) Fly() string {
return "Águia voando alto"
}
type Penguin struct{}
func (p Penguin) Eat() string {
return "Pinguim comendo peixe"
}
func (p Penguin) Move() string {
return "Pinguim caminhando"
}
func (p Penguin) Swim() string {
return "Pinguim nadando rapidamente"
}
// Funções que funcionam com qualquer subtipo
func FeedBird(bird Bird) {
fmt.Println(bird.Eat())
fmt.Println(bird.Move())
}
func MakeFlying(bird FlyingBird) {
fmt.Println(bird.Fly())
}
func MakeSwimming(bird SwimmingBird) {
fmt.Println(bird.Swim())
}
// ============================================================================
// 4. INTERFACE SEGREGATION PRINCIPLE (ISP)
// ============================================================================
// ❌ EXEMPLO RUIM: Interface "gorda" que força implementações desnecessárias
type BadMultiFunction interface {
Print() error
Scan() error
Fax() error
Email() error
}
type BadPrinter struct{}
func (p BadPrinter) Print() error {
fmt.Println("Imprimindo documento")
return nil
}
func (p BadPrinter) Scan() error {
// Impressora simples não faz scan!
return fmt.Errorf("esta impressora não tem scanner")
}
func (p BadPrinter) Fax() error {
// Impressora simples não envia fax!
return fmt.Errorf("esta impressora não tem fax")
}
func (p BadPrinter) Email() error {
// Impressora simples não envia email!
return fmt.Errorf("esta impressora não envia email")
}
// ✅ EXEMPLO BOM: Interfaces segregadas e específicas
type Printer interface {
Print() error
}
type Scanner interface {
Scan() error
}
type FaxMachine interface {
Fax() error
}
type EmailSender interface {
Email() error
}
// Implementações específicas
type SimplePrinter struct{}
func (p SimplePrinter) Print() error {
fmt.Println("Impressora simples: imprimindo")
return nil
}
type MultiFunctionPrinter struct{}
func (m MultiFunctionPrinter) Print() error {
fmt.Println("Multifuncional: imprimindo")
return nil
}
func (m MultiFunctionPrinter) Scan() error {
fmt.Println("Multifuncional: escaneando")
return nil
}
func (m MultiFunctionPrinter) Fax() error {
fmt.Println("Multifuncional: enviando fax")
return nil
}
func (m MultiFunctionPrinter) Email() error {
fmt.Println("Multifuncional: enviando email")
return nil
}
// Funções que usam apenas as interfaces necessárias
func PrintDocument(printer Printer) {
printer.Print()
}
func ScanDocument(scanner Scanner) {
scanner.Scan()
}
// ============================================================================
// 5. DEPENDENCY INVERSION PRINCIPLE (DIP)
// ============================================================================
// ❌ EXEMPLO RUIM: Dependência de implementações concretas
type BadEmailService struct{}
func (e *BadEmailService) Send(message string) {
fmt.Printf("Enviando email: %s\n", message)
}
type BadSMSService struct{}
func (s *BadSMSService) Send(message string) {
fmt.Printf("Enviando SMS: %s\n", message)
}
type BadNotificationService struct {
// Dependência DIRETA de implementações concretas
emailService *BadEmailService
smsService *BadSMSService
}
func (n *BadNotificationService) NotifyUser(message string, method string) {
switch method {
case "email":
// Acoplado ao BadEmailService
n.emailService.Send(message)
case "sms":
// Acoplado ao BadSMSService
n.smsService.Send(message)
}
// Para adicionar WhatsApp, preciso MODIFICAR esta classe!
}
// ✅ EXEMPLO BOM: Dependência de abstrações
type NotificationSender interface {
Send(message string) error
Type() string
}
// Implementações concretas
type EmailNotification struct{}
func (e EmailNotification) Send(message string) error {
fmt.Printf("📧 Email: %s\n", message)
return nil
}
func (e EmailNotification) Type() string {
return "email"
}
type SMSNotification struct{}
func (s SMSNotification) Send(message string) error {
fmt.Printf("📱 SMS: %s\n", message)
return nil
}
func (s SMSNotification) Type() string {
return "sms"
}
// NOVA implementação adicionada sem modificar o NotificationService
type WhatsAppNotification struct{}
func (w WhatsAppNotification) Send(message string) error {
fmt.Printf("💬 WhatsApp: %s\n", message)
return nil
}
func (w WhatsAppNotification) Type() string {
return "whatsapp"
}
type GoodNotificationService struct {
// Depende de ABSTRAÇÃO, não de implementação concreta
senders []NotificationSender
}
func NewNotificationService(senders []NotificationSender) *GoodNotificationService {
return &GoodNotificationService{senders: senders}
}
func (n *GoodNotificationService) AddSender(sender NotificationSender) {
n.senders = append(n.senders, sender)
}
func (n *GoodNotificationService) NotifyUser(message string, method string) error {
for _, sender := range n.senders {
if sender.Type() == method {
return sender.Send(message)
}
}
return fmt.Errorf("método de notificação '%s' não encontrado", method)
}
func (n *GoodNotificationService) BroadcastMessage(message string) {
fmt.Println("📢 Enviando para todos os canais:")
for _, sender := range n.senders {
sender.Send(message)
}
}
// ============================================================================
// EXEMPLOS DE USO
// ============================================================================
func main() {
fmt.Println("=== EXEMPLOS SOLID: RUIM vs BOM ===\n")
// 1. SRP - Comparação
fmt.Println("1. SINGLE RESPONSIBILITY PRINCIPLE:")
fmt.Println("❌ RUIM:")
badUser := &BadUserManager{
Name: "João",
Email: "[email protected]",
Password: "123456",
}
badUser.CreateUser()
fmt.Println("\n✅ BOM:")
goodService := &GoodUserService{
validator: &UserValidator{},
hasher: &PasswordHasher{},
repository: &UserRepository{},
email: &EmailService{},
logger: &Logger{},
}
goodService.CreateUser("Maria", "[email protected]", "123456")
fmt.Println("\n" + strings.Repeat("=", 50))
// 2. OCP - Comparação
fmt.Println("\n2. OPEN/CLOSED PRINCIPLE:")
fmt.Println("❌ RUIM:")
badCalc := &BadDiscountCalculator{}
fmt.Printf("Desconto VIP: R$ %.2f\n", badCalc.CalculateDiscount("vip", 100))
fmt.Printf("Desconto Student: R$ %.2f\n", badCalc.CalculateDiscount("student", 100))
fmt.Println("\n✅ BOM:")
goodCalc := &GoodDiscountCalculator{}
amount := 100.0
strategies := []DiscountStrategy{
VIPCustomerDiscount{},
StudentDiscount{}, // Adicionado sem modificar código existente!
}
for _, strategy := range strategies {
finalPrice, desc := goodCalc.ProcessOrder(amount, strategy)
fmt.Printf("R$ %.2f (%s)\n", finalPrice, desc)
}
fmt.Println("\n" + strings.Repeat("=", 50))
// 3. LSP - Comparação
fmt.Println("\n3. LISKOV SUBSTITUTION PRINCIPLE:")
fmt.Println("❌ RUIM (causaria panic):")
fmt.Println("// MakeBadBirdFly(BadPenguin{}) // <- Isso daria panic!")
fmt.Println("\n✅ BOM:")
eagle := Eagle{}
penguin := Penguin{}
FeedBird(eagle) // Funciona
FeedBird(penguin) // Também funciona
MakeFlying(eagle) // Específico para pássaros que voam
MakeSwimming(penguin) // Específico para pássaros que nadam
fmt.Println("\n" + strings.Repeat("=", 50))
// 4. ISP - Comparação
fmt.Println("\n4. INTERFACE SEGREGATION PRINCIPLE:")
fmt.Println("❌ RUIM:")
badPrinter := BadPrinter{}
badPrinter.Print() // Funciona
if err := badPrinter.Scan(); err != nil {
fmt.Printf("Erro: %s\n", err)
}
fmt.Println("\n✅ BOM:")
simplePrinter := SimplePrinter{}
multiFunctionPrinter := MultiFunctionPrinter{}
PrintDocument(simplePrinter) // Só precisa imprimir
PrintDocument(multiFunctionPrinter) // Também pode imprimir
ScanDocument(multiFunctionPrinter) // Só quem tem scanner
fmt.Println("\n" + strings.Repeat("=", 50))
// 5. DIP - Comparação
fmt.Println("\n5. DEPENDENCY INVERSION PRINCIPLE:")
fmt.Println("❌ RUIM:")
badNotificationService := &BadNotificationService{
emailService: &BadEmailService{},
smsService: &BadSMSService{},
}
badNotificationService.NotifyUser("Olá mundo!", "email")
// Para adicionar WhatsApp, preciso modificar BadNotificationService
fmt.Println("\n✅ BOM:")
goodNotificationService := NewNotificationService([]NotificationSender{
EmailNotification{},
SMSNotification{},
})
// Adicionando WhatsApp SEM modificar o código existente
goodNotificationService.AddSender(WhatsAppNotification{})
goodNotificationService.NotifyUser("Olá mundo!", "email")
goodNotificationService.NotifyUser("Olá mundo!", "whatsapp")
fmt.Println()
goodNotificationService.BroadcastMessage("Mensagem importante!")
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment