GoDasturchi
Dependency Injection

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.

example.go
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.

Hints (0/3)

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

OUTPUT

$ go run main.go
Kodingizni ishga tushiring

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.

example.go
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.

Hints (0/3)

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