Menu
Coddy logo textTech

Functional Options Deseni

Coddy'nin GO Journey'sinin Nesne Yönelimli Programlama bölümünün bir parçası. Ders 79 / 107.

Birçok isteğe bağlı yapılandırma alanına sahip yapılar oluştururken, kurucu işlevler kullanışsız hâle gelebilir. İşlevsel Seçenekler Deseni, nesneleri yapılandırmak için işlevleri kullanarak bu sorunu zarif bir şekilde çözer.

Birden fazla isteğe bağlı ayara sahip bir sunucu yapısı düşünün. Çok sayıda parametre içeren bir oluşturucu yerine, bir seçenek türü ve seçenek döndüren işlevler tanımlarız:

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(timeout int) Option {
    return func(s *Server) {
        s.timeout = timeout
    }
}

Yapıcı, değişken sayıda seçenek listesini kabul eder ve her birini uygular:

func NewServer(host string, opts ...Option) *Server {
    s := &Server{
        host:    host,
        port:    8080,    // varsayılan
        timeout: 30,      // varsayılan
    }
    for _, opt := range opts {
        opt(s)
    }
    return s
}

Artık sunucu oluşturma işlemi okunabilir ve esnek hale geliyor:

// Varsayılanları kullan
s1 := NewServer("localhost")

// Belirli seçenekleri özelleştir
s2 := NewServer("localhost", WithPort(3000), WithTimeout(60))

Bu desen, çağıranların yalnızca ihtiyaç duyduklarını belirtmesi, varsayılanların tek bir yerde açıkça tanımlanması ve yeni seçenekler eklemenin mevcut kodu bozmaması sayesinde öne çıkar. grpc ve zap gibi Go kütüphanelerinde yaygın olarak kullanılır.

challenge icon

Görev

Kolay

Fonksiyonel Seçenekler Deseni'ni kullanarak yapılandırılabilir bir veritabanı bağlantısı oluşturalım! Bu desen, özellikle veritabanı bağlantısının ihtiyaç duyduğu gibi, makul varsayılanlara sahip birçok isteğe bağlı ayar olduğunda öne çıkar.

Kodunuzu iki dosyaya ayıracaksınız:

  • database.go: Veritabanı bağlantı türünüzü ve seçenek işlevlerinizi tanımlayın.

    Şu dışa aktarılmamış alanlara sahip bir DBConnection yapısı oluşturun:

    • host (string)
    • port (int)
    • username (string)
    • password (string)
    • maxConnections (int)
    • timeout (int) - saniye cinsinden

    Bir Option'ı değiştiren bir işlev olarak *DBConnection türünü tanımlayın.

    Bir Option döndüren şu seçenek işlevlerini oluşturun:

    • WithPort(port int)
    • WithCredentials(username, password string)
    • WithMaxConnections(max int)
    • WithTimeout(seconds int)

    Bir NewDBConnection(host string, opts ...Option) döndüren *DBConnection kurucusunu oluşturun. Şu varsayılanları ayarlayın: port 5432, username "admin", password "secret", maxConnections 10, timeout 30. Varsayılanları ayarladıktan sonra sağlanan tüm seçenekleri uygulayın.

    Bağlantı bilgilerini şu biçimde döndüren bir ConnectionString() yöntemi ekleyin:

    [username]:[password]@[host]:[port] (max:[maxConnections], timeout:[timeout]s)
  • main.go: Çeşitli yapılandırmalarla veritabanı bağlantıları oluşturun.

    Host'u, ardından uygulanacak seçeneklerin sayısını okuyun. Her seçenek için seçenek türünü ve değerlerini okuyun:

    • port ve ardından port numarası
    • credentials ve ardından kullanıcı adı ile parola (iki satır)
    • maxconn ve ardından maksimum bağlantı sayısı
    • timeout ve ardından saniye cinsinden zaman aşımı

    Belirtilen seçeneklerle bir DBConnection oluşturun ve bağlantı dizesini yazdırın.

Aşağıdaki girdiler sağlanacaktır:

  • 1. satır: Host adı
  • 2. satır: Seçeneklerin sayısı
  • Sonraki satırlar: Seçenek türü ve değerleri

Örneğin, şu verildiğinde:

localhost
0

Çıktınız şu olmalıdır:

admin:secret@localhost:5432 (max:10, timeout:30s)

Ve şu verildiğinde:

db.example.com
2
port
3306
credentials
root
mypassword

Çıktınız şu olmalıdır:

root:mypassword@db.example.com:3306 (max:10, timeout:30s)

Ve şu verildiğinde:

production.server
4
port
5433
credentials
dbuser
securepass123
maxconn
50
timeout
60

Çıktınız şu olmalıdır:

dbuser:securepass123@production.server:5433 (max:50, timeout:60s)

Çağıranların yalnızca ihtiyaç duydukları seçenekleri belirttiğine dikkat edin: belirtilmeyen ayarlar makul varsayılanları kullanır. Fonksiyonel Seçenekler Deseni'nin zarafeti budur!

Kendin dene

package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
	"strings"
)

func main() {
	reader := bufio.NewReader(os.Stdin)

	// Host'u oku
	host, _ := reader.ReadString('\n')
	host = strings.TrimSpace(host)

	// Seçenek sayısını oku
	numOptionsStr, _ := reader.ReadString('\n')
	numOptions, _ := strconv.Atoi(strings.TrimSpace(numOptionsStr))

	// Seçenekleri topla
	var opts []Option

	for i := 0; i < numOptions; i++ {
		optionType, _ := reader.ReadString('\n')
		optionType = strings.TrimSpace(optionType)

		switch optionType {
		case "port":
			portStr, _ := reader.ReadString('\n')
			port, _ := strconv.Atoi(strings.TrimSpace(portStr))
			// TODO: WithPort seçeneğini opts'a ekle
			_ = port // Uygularken bu satırı kaldır

		case "credentials":
			username, _ := reader.ReadString('\n')
			username = strings.TrimSpace(username)
			password, _ := reader.ReadString('\n')
			password = strings.TrimSpace(password)
			// TODO: WithCredentials seçeneğini opts'a ekle
			_, _ = username, password // Uygularken bu satırı kaldır

		case "maxconn":
			maxStr, _ := reader.ReadString('\n')
			maxConn, _ := strconv.Atoi(strings.TrimSpace(maxStr))
			// TODO: WithMaxConnections seçeneğini opts'a ekle
			_ = maxConn // Uygularken bu satırı kaldır

		case "timeout":
			timeoutStr, _ := reader.ReadString('\n')
			timeout, _ := strconv.Atoi(strings.TrimSpace(timeoutStr))
			// TODO: WithTimeout seçeneğini opts'a ekle
			_ = timeout // Uygularken bu satırı kaldır
		}
	}

	// TODO: host ve opts ile NewDBConnection kullanarak DBConnection oluştur
	// TODO: ConnectionString() metodunu kullanarak bağlantı dizesini yazdır

	_ = opts // Uygularken bu satırı kaldır
	fmt.Println("TODO: Print connection string here")
}
quiz iconKendini test et

Bu ders kısa bir quiz içerir. Soruları yanıtlamak ve ilerlemeni kaydetmek için derse başla.

Nesne Yönelimli Programlama bölümündeki tüm dersler

Kendi başına pratik yap: Online Go derleyicisi