Un singur motiv de schimbare
Principiul responsabilității unice (Single Responsibility Principle) este S-ul din SOLID, cele cinci reguli pentru a proiecta cod care rămâne ușor de schimbat. El spune: un tip trebuie să aibă o singură sarcină — și deci un singur motiv de schimbare.
Când un tip salvează comenzi și trimite emailuri, el se schimbă atunci când se schimbă stocarea și atunci când se schimbă textul emailului. Două sarcini, două motive, risc dublu de a strica un lucru în timp ce îl atingi pe celălalt.
În Go regula se aplică structurilor, metodelor lor și pachetelor: păstrează fiecare parte concentrată pe o singură sarcină.
Prea multe sarcini într-un singur tip
Acest procesator de comenzi funcționează — dar el stochează comanda, scrie textul confirmării și îl „trimite”, toate într-o singură metodă. Testarea separată a textului emailului este imposibilă, iar refolosirea părții de stocare în altă parte înseamnă să cari după tine și codul de email.
Un singur tip care face totul
Process() amestecă două sarcini: stocarea și notificarea. Orice schimbare la oricare dintre ele înseamnă modificarea — și retestarea — aceluiași tip.
Ieșire: program Go și rezultatul capturat
package main
import "fmt"
type OrderProcessor struct{}
// Process face două lucruri: stochează ȘI notifică.
func (p OrderProcessor) Process(order string, customer string) {
fmt.Println("salvez comanda în stocare:", order)
fmt.Println("trimit email către", customer+":")
fmt.Println(" Mulțumim! Comanda ta", order, "a fost primită.")
}
func main() {
p := OrderProcessor{}
p.Process("#1042 (2 cărți)", "[email protected]")
}
O singură sarcină pentru fiecare tip
Soluția: câte un tip pentru fiecare sarcină. OrderStore doar stochează, EmailSender doar trimite. O funcție mică le coordonează.
Rezultatul afișat este același — dar acum fiecare parte poate fi schimbată, testată și refolosită separat.
Împărțit în două tipuri
Același comportament, dar separat: store-ul nu știe nimic despre emailuri, sender-ul nu știe nimic despre stocare. Funcția processOrder doar le leagă între ele.
Ieșire: program Go și rezultatul capturat
package main
import "fmt"
// OrderStore are o singură sarcină: stocarea comenzilor.
type OrderStore struct{}
func (s OrderStore) Save(order string) {
fmt.Println("salvez comanda în stocare:", order)
}
// EmailSender are o singură sarcină: trimiterea emailurilor.
type EmailSender struct{}
func (e EmailSender) SendConfirmation(customer, order string) {
fmt.Println("trimit email către", customer+":")
fmt.Println(" Mulțumim! Comanda ta", order, "a fost primită.")
}
func processOrder(order, customer string) {
store := OrderStore{}
sender := EmailSender{}
store.Save(order)
sender.SendConfirmation(customer, order)
}
func main() {
processOrder("#1042 (2 cărți)", "[email protected]")
}
Câștigul: refolosire fără teamă
Fiindcă sender-ul este un tip de sine stătător, el trimite și o notificare de expediere — fără niciun cod de stocare implicat. Iar store-ul arhivează o comandă fără să compună vreun email. Fiecare tip a crescut în interiorul sarcinii sale unice.
Ieșire: program Go și rezultatul capturat
package main
import "fmt"
type OrderStore struct{}
func (s OrderStore) Save(order string) {
fmt.Println("salvez comanda în stocare:", order)
}
func (s OrderStore) Archive(order string) {
fmt.Println("mut comanda în arhivă:", order)
}
type EmailSender struct{}
func (e EmailSender) SendConfirmation(customer, order string) {
fmt.Println("email către", customer+": comanda", order, "a fost primită")
}
func (e EmailSender) SendShippingNotice(customer, order string) {
fmt.Println("email către", customer+": comanda", order, "a fost expediată")
}
func main() {
store := OrderStore{}
sender := EmailSender{}
// Fiecare tip crește în interiorul sarcinii sale.
sender.SendShippingNotice("[email protected]", "#1042")
store.Archive("#0997")
}