Created
May 27, 2025 12:23
-
-
Save williamkoller/2aff1c9406528e32fde23383bbb39d60 to your computer and use it in GitHub Desktop.
SOLID em go
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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