Menu
Coddy logo textTech

Builder-Pattern in Go

Teil des Abschnitts Objektorientierte Programmierung der GO-Journey von Coddy — Lektion 80 von 107.

Das Builder-Pattern trennt die Konstruktion eines komplexen Objekts von seiner Darstellung. Im Gegensatz zum Functional-Options-Pattern verwendet der Builder ein dediziertes Builder-Struct mit Methoden, die das Objekt Schritt für Schritt konfigurieren.

So implementieren Sie einen Builder für eine HTTP-Anfrage:

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
}

Jede Methode gibt den Builder-Pointer zurück, was Methodenverkettung ermöglicht. Die Build()-Methode schließt den Vorgang ab und gibt das erstellte Objekt zurück:

req := NewRequestBuilder().
    Method("POST").
    URL("https://api.example.com").
    Header("Content-Type", "application/json").
    Build()

Das Builder-Pattern zeichnet sich aus, wenn Objekte mehrere Konfigurationsschritte erfordern oder wenn Sie eine bestimmte Konstruktionsreihenfolge erzwingen möchten. Es ist besonders nützlich für die Erstellung unveränderlicher Objekte oder wenn der Konstruktionsprozess selbst eine Validierung erfordert.

challenge icon

Aufgabe

Einfach

Lassen Sie uns einen E-Mail-Nachrichten-Composer mit dem Builder-Pattern erstellen! E-Mail-Nachrichten haben viele optionale Komponenten – Empfänger, CC, Betreff, Textkörper, Anhänge – was sie zu einem perfekten Kandidaten für die schrittweise Konstruktion mit Method Chaining macht.

Sie werden Ihren Code auf zwei Dateien verteilen:

  • email.go: Definieren Sie Ihre E-Mail-Struktur und ihren Builder.

    Erstellen Sie ein Email-Struct mit diesen Feldern:

    • from (string)
    • to (Slice von Strings)
    • cc (Slice von Strings)
    • subject (string)
    • body (string)

    Erstellen Sie ein EmailBuilder-Struct, das einen Pointer auf eine im Bau befindliche E-Mail hält. Implementieren Sie NewEmailBuilder(), das einen neuen Builder mit einer initialisierten E-Mail (leere Slices für to und cc) zurückgibt.

    Fügen Sie diese Builder-Methoden hinzu, die jeweils *EmailBuilder für das Chaining zurückgeben:

    • From(address string) - setzt den Absender
    • To(address string) - fügt einen Empfänger zum to-Slice hinzu
    • CC(address string) - fügt einen Empfänger zum cc-Slice hinzu
    • Subject(subject string) - setzt die Betreffzeile
    • Body(body string) - setzt den E-Mail-Textkörper

    Fügen Sie eine Build()-Methode hinzu, die die konstruierte *Email zurückgibt.

    Fügen Sie schließlich eine Summary()-Methode für Email hinzu, die einen String in diesem Format zurückgibt:

    From: [from]
    To: [comma-separated to addresses]
    CC: [comma-separated cc addresses or "none"]
    Subject: [subject]
    Body: [body]
  • main.go: Erstellen und Anzeigen von E-Mail-Nachrichten mit dem Builder.

    Lesen Sie die Absenderadresse ein, lesen Sie dann die Anzahl der Empfänger und jede Empfängeradresse. Lesen Sie als Nächstes die Anzahl der CC-Empfänger und jede CC-Adresse. Lesen Sie schließlich den Betreff und den Textkörper ein.

    Verwenden Sie den EmailBuilder mit Method Chaining, um die E-Mail zu konstruieren, und geben Sie dann deren Zusammenfassung aus.

Die folgenden Eingaben werden bereitgestellt:

  • Zeile 1: Absenderadresse
  • Zeile 2: Anzahl der Empfänger
  • Folgende Zeilen: Jede Empfängeradresse
  • Nächste Zeile: Anzahl der CC-Empfänger
  • Folgende Zeilen: Jede CC-Adresse
  • Nächste Zeile: Betreff
  • Letzte Zeile: Textkörper

Zum Beispiel, gegeben:

alice@company.com
2
bob@company.com
carol@company.com
1
manager@company.com
Weekly Report
Please find the weekly report attached.

Ihre Ausgabe sollte sein:

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.

Und gegeben:

support@service.com
1
customer@email.com
0
Your Ticket Update
Your support ticket has been resolved.

Ihre Ausgabe sollte sein:

From: support@service.com
To: customer@email.com
CC: none
Subject: Your Ticket Update
Body: Your support ticket has been resolved.

Beachten Sie, wie der Builder es Ihnen ermöglicht, mehrere Empfänger nacheinander durch wiederholte To()-Aufrufe hinzuzufügen, und wie das Pattern den Konstruktionsprozess selbst bei vielen optionalen Feldern sauber und lesbar hält.

Spickzettel

Das Builder-Pattern trennt die Konstruktion eines komplexen Objekts von seiner Darstellung, indem es ein spezielles Builder-Struct mit Methoden verwendet, die das Objekt Schritt für Schritt konfigurieren.

Grundstruktur:

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-Methoden geben den Builder-Pointer zurück, um Method Chaining (Methodenverkettung) zu ermöglichen:

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
}

Die Build()-Methode schließt den Vorgang ab und gibt das konstruierte Objekt zurück:

func (b *RequestBuilder) Build() *Request {
    return b.request
}

Verwendung mit Method Chaining:

req := NewRequestBuilder().
    Method("POST").
    URL("https://api.example.com").
    Header("Content-Type", "application/json").
    Build()

Das Builder-Pattern ist nützlich, wenn Objekte mehrere Konfigurationsschritte erfordern, wenn eine bestimmte Konstruktionsreihenfolge erzwungen werden soll, zur Erstellung unveränderlicher (immutable) Objekte oder wenn der Konstruktionsprozess eine Validierung benötigt.

Probier es selbst

package main

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

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

	// Absenderadresse lesen
	from, _ := reader.ReadString('\n')
	from = strings.TrimSpace(from)

	// Anzahl der Empfänger lesen
	toCountStr, _ := reader.ReadString('\n')
	toCount, _ := strconv.Atoi(strings.TrimSpace(toCountStr))

	// Jede Empfängeradresse lesen
	toAddresses := make([]string, toCount)
	for i := 0; i < toCount; i++ {
		addr, _ := reader.ReadString('\n')
		toAddresses[i] = strings.TrimSpace(addr)
	}

	// Anzahl der CC-Empfänger lesen
	ccCountStr, _ := reader.ReadString('\n')
	ccCount, _ := strconv.Atoi(strings.TrimSpace(ccCountStr))

	// Jede CC-Adresse lesen
	ccAddresses := make([]string, ccCount)
	for i := 0; i < ccCount; i++ {
		addr, _ := reader.ReadString('\n')
		ccAddresses[i] = strings.TrimSpace(addr)
	}

	// Betreff lesen
	subject, _ := reader.ReadString('\n')
	subject = strings.TrimSpace(subject)

	// Textkörper lesen
	body, _ := reader.ReadString('\n')
	body = strings.TrimSpace(body)

	// TODO: Verwenden Sie den EmailBuilder mit Methodenverkettung, um die E-Mail zu erstellen
	// Beginnen Sie mit NewEmailBuilder(), verketten Sie dann From(), To(), CC(), Subject(), Body()
	// Rufen Sie schließlich Build() auf, um die E-Mail zu erhalten

	// TODO: Geben Sie die E-Mail-Zusammenfassung mit der Methode Summary() aus
}
quiz iconTeste dich selbst

Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.

Alle Lektionen in Objektorientierte Programmierung