GoDasturchi
Functional Options Pattern

Functional Options Pattern

Funksional sozlamalar naqshi

Tasavvur qiling, kofe buyurtma qilyapsiz. Ba'zan shunchaki "kofe" deysiz (standart), ba'zan "kofe, sut bilan", ba'zan "kofe, sut bilan, shakarsiz, katta stakanda". Har bir kombinatsiya uchun alohida menyu bandi yozish ma'nosiz — buning o'rniga, siz standart kofega ustiga ixtiyoriy qo'shimchalar aytasiz.

Dasturda ham xuddi shunday muammo bor: bir funksiya (masalan server yaratish) ko'plab ixtiyoriy sozlamaga ega bo'lishi mumkin (port, timeout, log darajasi...). Agar hammasini oddiy parametr qilib bersangiz, funksiya imzosi cheksiz uzun bo'lib ketadi, va har birini har safar yozish shart bo'lib qoladi, hatto standart qiymat kifoya qilsa ham.

Functional Options naqshi buni hal qiladi: siz "standart" konfiguratsiya bilan boshlaysiz, so'ng unga funksiyalar ko'rinishidagi ixtiyoriy "o'zgartirishlar"ni beraverasiz — xuddi kofega qo'shimchalarni aytgandek.

example.go
package main

import "fmt"

type Server struct {
	Host    string
	Port    int
	Timeout int
}

type Option func(*Server)

func WithPort(port int) Option {
	return func(s *Server) { s.Port = port }
}

func WithTimeout(seconds int) Option {
	return func(s *Server) { s.Timeout = seconds }
}

func NewServer(host string, opts ...Option) *Server {
	s := &Server{Host: host, Port: 8080, Timeout: 30} // standart qiymatlar
	for _, opt := range opts {
		opt(s)
	}
	return s
}

func main() {
	s1 := NewServer("localhost")
	fmt.Println(s1.Port, s1.Timeout)

	s2 := NewServer("localhost", WithPort(9090), WithTimeout(60))
	fmt.Println(s2.Port, s2.Timeout)
}

Option — bu shunchaki "*Serverni oladigan va uni o'zgartiradigan" funksiya turi. WithPort(9090) chaqirilganda, u darhol port'ni 9090 qilib qo'ymaydi — u shunday qiladigan kichik funksiya qaytaradi. NewServer esa avval standart qiymatlar bilan Server yaratadi, so'ng unga berilgan har bir "Option" funksiyasini birma-bir chaqirib, kerakli maydonlarni o'zgartiradi.

Bu naqshning go'zalligi: NewServer("localhost") — hech qanday qo'shimcha sozlamasiz, eng sodda chaqiruv ham ishlaydi. Va agar kelajakda yana beshta yangi sozlama qo'shish kerak bo'lsa, NewServerning imzosi o'zgarmaydi — shunchaki yangi WithXxx funksiyasi qo'shiladi, eski chaqiruvchi kod buzilmaydi.

>_ Exercise

Server'ga yangi ixtiyoriy sozlama qo'shing.

  • WithHost(host string) Option funksiyasini yozing: s.Host'ni o'zgartirsin
  • MaxConnections maydonini Server'ga qo'shing (standart qiymati 100)
  • WithMaxConnections(n int) Option yozing
  • NewServer("default-host", WithHost("custom"), WithMaxConnections(500)) chaqirib, Host va MaxConnections'ni chop eting

Stuck? Reveal a hint to help you.

Hints (0/3)

Key Takeaway

Key Takeaway:

Functional Options naqshi ko'plab ixtiyoriy sozlamaga ega konstruktorlarni sodda, o'qilishi oson va kelajakda kengaytirish oson qiladi — standart qiymatlardan boshlab, faqat kerakli narsani "Option" funksiyalari bilan o'zgartirasiz.

NEXT UP

Constructor Functions (NewXxx)

OUTPUT

$ go run main.go
Kodingizni ishga tushiring

Functional Options Pattern

Funksional sozlamalar naqshi

Tasavvur qiling, kofe buyurtma qilyapsiz. Ba'zan shunchaki "kofe" deysiz (standart), ba'zan "kofe, sut bilan", ba'zan "kofe, sut bilan, shakarsiz, katta stakanda". Har bir kombinatsiya uchun alohida menyu bandi yozish ma'nosiz — buning o'rniga, siz standart kofega ustiga ixtiyoriy qo'shimchalar aytasiz.

Dasturda ham xuddi shunday muammo bor: bir funksiya (masalan server yaratish) ko'plab ixtiyoriy sozlamaga ega bo'lishi mumkin (port, timeout, log darajasi...). Agar hammasini oddiy parametr qilib bersangiz, funksiya imzosi cheksiz uzun bo'lib ketadi, va har birini har safar yozish shart bo'lib qoladi, hatto standart qiymat kifoya qilsa ham.

Functional Options naqshi buni hal qiladi: siz "standart" konfiguratsiya bilan boshlaysiz, so'ng unga funksiyalar ko'rinishidagi ixtiyoriy "o'zgartirishlar"ni beraverasiz — xuddi kofega qo'shimchalarni aytgandek.

example.go
package main

import "fmt"

type Server struct {
	Host    string
	Port    int
	Timeout int
}

type Option func(*Server)

func WithPort(port int) Option {
	return func(s *Server) { s.Port = port }
}

func WithTimeout(seconds int) Option {
	return func(s *Server) { s.Timeout = seconds }
}

func NewServer(host string, opts ...Option) *Server {
	s := &Server{Host: host, Port: 8080, Timeout: 30} // standart qiymatlar
	for _, opt := range opts {
		opt(s)
	}
	return s
}

func main() {
	s1 := NewServer("localhost")
	fmt.Println(s1.Port, s1.Timeout)

	s2 := NewServer("localhost", WithPort(9090), WithTimeout(60))
	fmt.Println(s2.Port, s2.Timeout)
}

Option — bu shunchaki "*Serverni oladigan va uni o'zgartiradigan" funksiya turi. WithPort(9090) chaqirilganda, u darhol port'ni 9090 qilib qo'ymaydi — u shunday qiladigan kichik funksiya qaytaradi. NewServer esa avval standart qiymatlar bilan Server yaratadi, so'ng unga berilgan har bir "Option" funksiyasini birma-bir chaqirib, kerakli maydonlarni o'zgartiradi.

Bu naqshning go'zalligi: NewServer("localhost") — hech qanday qo'shimcha sozlamasiz, eng sodda chaqiruv ham ishlaydi. Va agar kelajakda yana beshta yangi sozlama qo'shish kerak bo'lsa, NewServerning imzosi o'zgarmaydi — shunchaki yangi WithXxx funksiyasi qo'shiladi, eski chaqiruvchi kod buzilmaydi.

>_ Exercise

Server'ga yangi ixtiyoriy sozlama qo'shing.

  • WithHost(host string) Option funksiyasini yozing: s.Host'ni o'zgartirsin
  • MaxConnections maydonini Server'ga qo'shing (standart qiymati 100)
  • WithMaxConnections(n int) Option yozing
  • NewServer("default-host", WithHost("custom"), WithMaxConnections(500)) chaqirib, Host va MaxConnections'ni chop eting

Stuck? Reveal a hint to help you.

Hints (0/3)

Key Takeaway

Key Takeaway:

Functional Options naqshi ko'plab ixtiyoriy sozlamaga ega konstruktorlarni sodda, o'qilishi oson va kelajakda kengaytirish oson qiladi — standart qiymatlardan boshlab, faqat kerakli narsani "Option" funksiyalari bilan o'zgartirasiz.

NEXT UP

Constructor Functions (NewXxx)