Dependency Injection
Bog'liqlikni tashqaridan berish
Oshpazni tasavvur qiling: agar u kerakli barcha mahsulotni o'zi, doim bozorga chiqib topishi kerak bo'lsa, uning ishi sekinlashadi va u faqat bitta bozorga "bog'liq" bo'lib qoladi. Aksincha, agar unga kerakli mahsulotlar tayyor holda berilsa ("mana sizga sabzavotlar, mana go'sht"), oshpaz faqat pishirish bilan shug'ullanadi, va mahsulotni qayerdan olish — boshqa birovning ishi.
Dependency Injection (DI, "bog'liqlikni tashqaridan berish") — aynan shu g'oya: bir komponent o'ziga kerakli bog'liqlikni (masalan baza ulanishi, logger, boshqa servis) o'zi yaratmaydi, uni tashqaridan, odatda konstruktor orqali oladi. Buni aslida oldingi darsda (NewService(logger Logger)) allaqachon ko'rgan edingiz — bu DI'ning eng sodda ko'rinishi edi.
package main
import "fmt"
type Notifier interface {
Send(msg string)
}
type SMSNotifier struct{}
func (s SMSNotifier) Send(msg string) { fmt.Println("SMS:", msg) }
// Yomon: OrderService o'zi SMSNotifier'ni yaratadi — bog'liq, testlash qiyin
type OrderServiceBad struct {
notifier SMSNotifier
}
// Yaxshi: bog'liqlik tashqaridan (konstruktor orqali) beriladi
type OrderService struct {
notifier Notifier
}
func NewOrderService(n Notifier) *OrderService {
return &OrderService{notifier: n}
}
func (s *OrderService) PlaceOrder() {
s.notifier.Send("buyurtmangiz qabul qilindi")
}
func main() {
svc := NewOrderService(SMSNotifier{})
svc.PlaceOrder()
}OrderServiceBad bilan OrderService orasidagi farq — bir qarashda kichik tuyulishi mumkin, lekin uning oqibati katta: OrderServiceBad faqat SMSNotifier bilan ishlay oladi, uni boshqa turdagi xabar yuborish usuli (email, push-bildirishnoma) bilan almashtirish uchun OrderServiceBadning o'zini o'zgartirish kerak bo'ladi. OrderService esa Notifier interfeysi bilan ishlagani uchun, istalgan mos turni qabul qila oladi — bu "Interface-Based Design" darsida ko'rgan tamoyilning to'g'ridan-to'g'ri davomi.
DI'ning eng katta amaliy foydasi — testlash. Haqiqiy SMS yubormasdan, OrderServiceni sinash uchun sizga faqat Notifier interfeysini amalga oshiruvchi, hech qanday haqiqiy tarmoq so'rovi qilmaydigan soxta (fake) tur kerak — buni "Mocking Dependencies" darsida to'liq ko'rgan edingiz.
>_ Exercise
PaymentProcessor'ga to'lov usulini tashqaridan bering.
- •PaymentGateway interfeysini yozing: Charge(amount int) string
- •CardGateway struct'i (Charge metodi "karta orqali X to'landi" qaytarsin)
- •PaymentProcessor struct'i (gateway PaymentGateway maydoni), NewPaymentProcessor(g PaymentGateway) konstruktori
- •Process(amount int) string metodi — gateway.Charge(amount) natijasini qaytarsin
- •NewPaymentProcessor(CardGateway{}) yaratib, Process(50000) natijasini chop eting
Stuck? Reveal a hint to help you.
Key Takeaway
Key Takeaway:
Dependency Injection — komponentga kerakli bog'liqlikni o'zi yaratdirmasdan, tashqaridan (odatda konstruktor orqali) berish; bu kodni moslashuvchan va testlash oson qiladi.
NEXT UP
Table-Driven Design
$ go run main.go
Kodingizni ishga tushiring