Go'da Builder Deseni
Coddy'nin GO Journey'sinin Nesne Yönelimli Programlama bölümünün bir parçası — ders 80 / 107.
Builder Deseni, karmaşık bir nesnenin oluşturulmasını temsilinden ayırır. Functional Options deseninin aksine Builder, nesneyi adım adım yapılandıran metotlara sahip özel bir builder yapısı (struct) kullanır.
Bir HTTP isteği için bir oluşturucunun (builder) nasıl uygulanacağı aşağıda açıklanmıştır:
type Request struct {
method string
url string
headers map[string]string
body string
}
type RequestBuilder struct {
request *Request
}
func NewRequestBuilder() *RequestBuilder {
return &RequestBuilder{
request: &Request{
headers: make(map[string]string),
},
}
}
func (b *RequestBuilder) Method(m string) *RequestBuilder {
b.request.method = m
return b
}
func (b *RequestBuilder) URL(u string) *RequestBuilder {
b.request.url = u
return b
}
func (b *RequestBuilder) Header(key, value string) *RequestBuilder {
b.request.headers[key] = value
return b
}
func (b *RequestBuilder) Build() *Request {
return b.request
}Her metot, metot zincirlemeye olanak tanıyan oluşturucu işaretçisini döndürür. Build() metodu, oluşturulan nesneyi sonlandırır ve döndürür:
req := NewRequestBuilder().
Method("POST").
URL("https://api.example.com").
Header("Content-Type", "application/json").
Build()Builder deseni, nesneler birden fazla yapılandırma adımı gerektirdiğinde veya belirli bir oluşturma sırasını zorunlu kılmak istediğinizde öne çıkar. Özellikle değişmez (immutable) nesneler oluşturmak için veya oluşturma sürecinin kendisinin doğrulanması gerektiğinde yararlıdır.
Görev
KolayBuilder Pattern kullanarak bir e-posta mesajı oluşturucu inşa edelim! E-posta mesajları; alıcılar, CC, konu, gövde, ekler gibi birçok isteğe bağlı bileşene sahiptir ve bu da onları metot zincirleme (method chaining) ile adım adım oluşturma için mükemmel bir aday yapar.
Kodunuzu iki dosya halinde düzenleyeceksiniz:
email.go: E-posta yapınızı ve oluşturucusunu (builder) tanımlayın.Şu alanlara sahip bir
Emailyapısı (struct) oluşturun:from(string)to(string dilimi/slice)cc(string dilimi/slice)subject(string)body(string)
İnşa edilmekte olan bir Email'e işaretçi (pointer) tutan bir
EmailBuilderyapısı oluşturun. Başlatılmış bir Email (tovecciçin boş dilimler) ile yeni bir oluşturucu döndürenNewEmailBuilder()fonksiyonunu uygulayın.Zincirleme için her biri
*EmailBuilderdöndüren şu oluşturucu metotlarını ekleyin:From(address string)- göndereni ayarlarTo(address string)-todilimine bir alıcı eklerCC(address string)-ccdilimine bir alıcı eklerSubject(subject string)- konu satırını ayarlarBody(body string)- e-posta gövdesini ayarlar
Oluşturulan
*Emailnesnesini döndüren birBuild()metodu ekleyin.Son olarak, Email üzerinde şu formatta bir string döndüren bir
Summary()metodu ekleyin:From: [from] To: [comma-separated to addresses] CC: [comma-separated cc addresses or "none"] Subject: [subject] Body: [body]main.go: Oluşturucuyu kullanarak e-posta mesajları oluşturun ve görüntüleyin.Gönderen adresini okuyun, ardından alıcı sayısını ve her bir alıcı adresini okuyun. Sonra, CC alıcı sayısını ve her bir CC adresini okuyun. Son olarak, konuyu ve gövdeyi okuyun.
E-postayı oluşturmak için metot zincirleme ile EmailBuilder'ı kullanın, ardından özetini yazdırın.
Aşağıdaki girdiler sağlanacaktır:
- Satır 1: Gönderen adresi
- Satır 2: Alıcı sayısı
- Takip eden satırlar: Her bir alıcı adresi
- Sonraki satır: CC alıcı sayısı
- Takip eden satırlar: Her bir CC adresi
- Sonraki satır: Konu
- Son satır: Gövde
Örneğin, şu girdi verildiğinde:
alice@company.com
2
bob@company.com
carol@company.com
1
manager@company.com
Weekly Report
Please find the weekly report attached.Çıktınız şu olmalıdır:
From: alice@company.com
To: bob@company.com, carol@company.com
CC: manager@company.com
Subject: Weekly Report
Body: Please find the weekly report attached.Ve şu girdi verildiğinde:
support@service.com
1
customer@email.com
0
Your Ticket Update
Your support ticket has been resolved.Çıktınız şu olmalıdır:
From: support@service.com
To: customer@email.com
CC: none
Subject: Your Ticket Update
Body: Your support ticket has been resolved.Oluşturucunun (builder), tekrarlanan To() çağrıları aracılığıyla birden fazla alıcıyı tek tek eklemenize nasıl izin verdiğine ve bu desenin, birçok isteğe bağlı alan olsa bile oluşturma sürecini nasıl temiz ve okunabilir tuttuğuna dikkat edin.
Kopya kağıdı
Builder Deseni, karmaşık bir nesnenin oluşturulmasını, nesneyi adım adım yapılandıran yöntemlere sahip özel bir builder yapısı (struct) kullanarak temsilinden ayırır.
Temel yapı:
type Request struct {
method string
url string
headers map[string]string
body string
}
type RequestBuilder struct {
request *Request
}
func NewRequestBuilder() *RequestBuilder {
return &RequestBuilder{
request: &Request{
headers: make(map[string]string),
},
}
}Builder yöntemleri, yöntem zincirlemeyi (method chaining) mümkün kılmak için builder işaretçisini (pointer) döndürür:
func (b *RequestBuilder) Method(m string) *RequestBuilder {
b.request.method = m
return b
}
func (b *RequestBuilder) URL(u string) *RequestBuilder {
b.request.url = u
return b
}
func (b *RequestBuilder) Header(key, value string) *RequestBuilder {
b.request.headers[key] = value
return b
}Build() yöntemi, oluşturulan nesneyi sonlandırır ve döndürür:
func (b *RequestBuilder) Build() *Request {
return b.request
}Yöntem zincirleme ile kullanım:
req := NewRequestBuilder().
Method("POST").
URL("https://api.example.com").
Header("Content-Type", "application/json").
Build()Builder deseni; nesneler birden fazla yapılandırma adımı gerektirdiğinde, belirli bir oluşturma sırasını zorunlu kılarken, değişmez (immutable) nesneler oluştururken veya oluşturma sürecinin doğrulanması (validation) gerektiğinde kullanışlıdır.
Kendin dene
package main
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
)
func main() {
reader := bufio.NewReader(os.Stdin)
// Gönderen adresini oku
from, _ := reader.ReadString('\n')
from = strings.TrimSpace(from)
// Alıcı sayısını oku
toCountStr, _ := reader.ReadString('\n')
toCount, _ := strconv.Atoi(strings.TrimSpace(toCountStr))
// Her bir alıcı adresini oku
toAddresses := make([]string, toCount)
for i := 0; i < toCount; i++ {
addr, _ := reader.ReadString('\n')
toAddresses[i] = strings.TrimSpace(addr)
}
// CC alıcı sayısını oku
ccCountStr, _ := reader.ReadString('\n')
ccCount, _ := strconv.Atoi(strings.TrimSpace(ccCountStr))
// Her bir CC adresini oku
ccAddresses := make([]string, ccCount)
for i := 0; i < ccCount; i++ {
addr, _ := reader.ReadString('\n')
ccAddresses[i] = strings.TrimSpace(addr)
}
// Konuyu oku
subject, _ := reader.ReadString('\n')
subject = strings.TrimSpace(subject)
// Gövdeyi oku
body, _ := reader.ReadString('\n')
body = strings.TrimSpace(body)
// TODO: E-postayı oluşturmak için metot zincirleme (method chaining) ile EmailBuilder kullanın
// NewEmailBuilder() ile başlayın, ardından From(), To(), CC(), Subject(), Body() metotlarını zincirleyin
// Son olarak, Email nesnesini elde etmek için Build() metodunu çağırın
// TODO: Summary() metodunu kullanarak e-posta özetini yazdırın
}
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
1Go OOP Temelleri
Harici DosyalarGo Çalışma Alanı ve ModüllerPaketler ve İçe AktarmalarDışa Aktarılan ve Aktarılmayan İsimlerGo'da OOP'ye GirişSınıf Olarak Struct'larStruct'larda Metot TanımlamaPointer ve Değer AlıcılarStruct BaşlatmaYapıcı FonksiyonlarÖzet - Basit Hesap Makinesi4Arayüzler
Arayüzlere GirişÖrtük UygulamaSözleşme Olarak ArayüzBoş Arayüz (any)Tür OnaylamaTür SeçimiArayüz BileşimiStringer ve Error ArayüzleriÖzet - Şekil Hesaplayıcı7Kapsülleme
Dışa Aktarılan ve Aktarılmayan AlanlarPaket Seviyesinde KapsüllemeGetter ve Setter MetotlarıGo'da Bilgi GizlemeÖzet - Öğrenci Kayıtları10Generics (Go 1.18+)
Generics'e GirişTür ParametreleriTür KısıtlamalarıGeneric Struct'larGeneric Metotlar İçin Geçici ÇözümÖzet - Generic Koleksiyon13Tasarım Kalıpları Bölüm 1
Tasarım Kalıplarına GirişSingleton KalıbıFactory KalıbıAbstract Factory KalıbıObserver KalıbıStrategy Kalıbı2Türler ve Struct'lar: Derinlemesine İnceleme
Temel ve Bileşik TürlerÖzel Tür TanımlamalarıStruct EtiketleriAnonim Struct'larİç İçe Geçmiş Struct'larSıfır Değerler ve VarsayılanlarÖzet - Rehber5Kalıtım Yerine Kompozisyon
Go'da Neden Kalıtım YokStruct Gömme TemelleriMetot YükseltmeBirden Fazla Struct GömmeGömme vs AgregasyonGömülü Metotları GölgelemeÖzet - Çalışan Hiyerarşisi8Hata Yönetimi ve OOP
error ArayüzüÖzel Hata TürleriHata Sarmalama (fmt.Errorf)Sentinel Hatalarerrors.Is() ve errors.As()Panic, Defer ve RecoverÖzet - Dosya Ayrıştırıcı3İşaretçiler ve Bellek
Go'da İşaretçi TemelleriStruct İşaretçileriDeğer ile Geçme ve Referans ile Geçmenew() FonksiyonuGo'da Garbage CollectionÖzet - Linked List Oluşturucu6Go'da Polimorfizm
Interface'ler ile PolimorfizmGo'da Duck TypingInterface Karşılama KurallarıPolimorfik KoleksiyonlarDependency InjectionÖzet - Payment Processor9Eşzamanlılık ve OOP
Goroutine TemelleriKanallar ve İletişimTamponlu ve Tamponsuz KanallarSelect İfadesisync.Mutex ve sync.RWMutexsync.WaitGroupThread-Safe Struct TasarımıÖzet - Worker Pool12İleri Düzey OOP Kavramları
Functional Options DeseniGo'da Builder DeseniMetot ZincirlemeTür Takma Adları vs. TanımlamalarReflection TemelleriKod Üretimine Genel Bakış