Menu
Coddy logo textTech

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.

challenge icon

Görev

Kolay

Builder 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 Email yapı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 EmailBuilder yapısı oluşturun. Başlatılmış bir Email (to ve cc için boş dilimler) ile yeni bir oluşturucu döndüren NewEmailBuilder() fonksiyonunu uygulayın.

    Zincirleme için her biri *EmailBuilder döndüren şu oluşturucu metotlarını ekleyin:

    • From(address string) - göndereni ayarlar
    • To(address string) - to dilimine bir alıcı ekler
    • CC(address string) - cc dilimine bir alıcı ekler
    • Subject(subject string) - konu satırını ayarlar
    • Body(body string) - e-posta gövdesini ayarlar

    Oluşturulan *Email nesnesini döndüren bir Build() 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
}
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