Wzorzec Builder w Go
Część sekcji Programowanie obiektowe ścieżki GO w Coddy. Lekcja 80 z 107.
Wzorzec Builder oddziela tworzenie złożonego obiektu od jego reprezentacji. W przeciwieństwie do wzorca Functional Options, Builder wykorzystuje dedykowaną strukturę konstruktora z metodami, które konfigurują obiekt krok po kroku.
Oto, jak zaimplementować budowniczego żądania HTTP:
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
}Każda metoda zwraca wskaźnik do obiektu buildera, umożliwiając łączenie metod. Metoda Build() finalizuje i zwraca skonstruowany obiekt:
req := NewRequestBuilder().
Method("POST").
URL("https://api.example.com").
Header("Content-Type", "application/json").
Build()Wzorzec Builder sprawdza się doskonale, gdy obiekty wymagają wielu kroków konfiguracji lub gdy chcesz wymusić określoną kolejność tworzenia. Jest szczególnie przydatny przy tworzeniu niezmiennych obiektów lub gdy sam proces tworzenia wymaga walidacji.
Wyzwanie
ŁatwyZbudujmy kompozytor wiadomości e-mail z użyciem wzorca Builder! Wiadomości e-mail mają wiele opcjonalnych elementów: odbiorców, DW, temat, treść i załączniki, dzięki czemu doskonale nadają się do konstruowania krok po kroku z łańcuchowym wywoływaniem metod.
Uporządkujesz swój kod w dwóch plikach:
email.go: Zdefiniuj strukturę wiadomości e-mail i jej builder.Utwórz strukturę
Emailz następującymi polami:from(string)to(wycinek ciągów znaków)cc(wycinek ciągów znaków)subject(string)body(string)
Utwórz strukturę
EmailBuilder, która przechowuje wskaźnik do konstruowanego obiektu Email. ZaimplementujNewEmailBuilder(), która zwraca nowy builder z zainicjowanym obiektem Email (puste wycinki dlatoicc).Dodaj następujące metody buildera, z których każda zwraca
*EmailBuilder, aby umożliwić łańcuchowe wywoływanie:From(address string)— ustawia adres nadawcyTo(address string)— dodaje odbiorcę do wycinkatoCC(address string)— dodaje odbiorcę do wycinkaccSubject(subject string)— ustawia tematBody(body string)— ustawia treść wiadomości e-mail
Dodaj metodę
Build(), która zwraca skonstruowany obiekt*Email.Na koniec dodaj metodę
Summary()do Email, która zwraca ciąg znaków w następującym formacie:From: [from] To: [comma-separated to addresses] CC: [comma-separated cc addresses or "none"] Subject: [subject] Body: [body]main.go: Twórz i wyświetlaj wiadomości e-mail za pomocą buildera.Odczytaj adres nadawcy, a następnie liczbę odbiorców i adres każdego z nich. Następnie odczytaj liczbę odbiorców DW i adres każdego z nich. Na koniec odczytaj temat i treść wiadomości.
Użyj EmailBuildera z łańcuchowym wywoływaniem metod, aby skonstruować wiadomość e-mail, a następnie wyświetl jej podsumowanie.
Dane wejściowe będą miały następującą postać:
- Wiersz 1: Adres nadawcy
- Wiersz 2: Liczba odbiorców
- Kolejne wiersze: Adres każdego odbiorcy
- Następny wiersz: Liczba odbiorców DW
- Kolejne wiersze: Adres każdego odbiorcy DW
- Następny wiersz: Temat
- Ostatni wiersz: Treść wiadomości
Na przykład dla danych:
alice@company.com
2
bob@company.com
carol@company.com
1
manager@company.com
Weekly Report
Please find the weekly report attached.Wynik powinien być następujący:
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.A dla danych:
support@service.com
1
customer@email.com
0
Your Ticket Update
Your support ticket has been resolved.Wynik powinien być następujący:
From: support@service.com
To: customer@email.com
CC: none
Subject: Your Ticket Update
Body: Your support ticket has been resolved.Zwróć uwagę, że builder pozwala dodawać wielu odbiorców pojedynczo za pomocą kolejnych wywołań To(), a wzorzec sprawia, że proces konstruowania pozostaje przejrzysty i czytelny nawet przy wielu opcjonalnych polach.
Spróbuj swoich sił
package main
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
)
func main() {
reader := bufio.NewReader(os.Stdin)
// Odczytaj adres nadawcy
from, _ := reader.ReadString('\n')
from = strings.TrimSpace(from)
// Odczytaj liczbę odbiorców
toCountStr, _ := reader.ReadString('\n')
toCount, _ := strconv.Atoi(strings.TrimSpace(toCountStr))
// Odczytaj adres każdego odbiorcy
toAddresses := make([]string, toCount)
for i := 0; i < toCount; i++ {
addr, _ := reader.ReadString('\n')
toAddresses[i] = strings.TrimSpace(addr)
}
// Odczytaj liczbę odbiorców CC
ccCountStr, _ := reader.ReadString('\n')
ccCount, _ := strconv.Atoi(strings.TrimSpace(ccCountStr))
// Odczytaj każdy adres CC
ccAddresses := make([]string, ccCount)
for i := 0; i < ccCount; i++ {
addr, _ := reader.ReadString('\n')
ccAddresses[i] = strings.TrimSpace(addr)
}
// Odczytaj temat
subject, _ := reader.ReadString('\n')
subject = strings.TrimSpace(subject)
// Odczytaj treść
body, _ := reader.ReadString('\n')
body = strings.TrimSpace(body)
// TODO: Użyj EmailBuilder z łańcuchowym wywoływaniem metod, aby utworzyć wiadomość e-mail
// Zacznij od NewEmailBuilder(), a następnie wywołaj łańcuchowo From(), To(), CC(), Subject(), Body()
// Na koniec wywołaj Build(), aby uzyskać Email
// TODO: Wypisz podsumowanie wiadomości e-mail za pomocą metody Summary()
}
Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.
Wszystkie lekcje w sekcji Programowanie obiektowe
1Podstawy OOP w Go
Pliki zewnętrzneObszar roboczy i moduły GoPakiety i importyNazwy eksportowane i nieeksportowaneWprowadzenie do OOP w GoStruktury jako klasyDefiniowanie metod dla strukturOdbiorniki wskaźnikowe i wartościoweInicjalizacja strukturFunkcje konstruktoraPodsumowanie – prosty kalkulator4Interfejsy
Wprowadzenie do interfejsówImplementacja niejawnaInterfejs jako kontraktPusty interfejs (any)Asercja typuPrzełącznik typówKompozycja interfejsówInterfejsy Stringer i ErrorPowtórka — kalkulator figur7Hermetyzacja
Pola eksportowane i nieeksportowaneHermetyzacja na poziomie pakietuMetody pobierające i ustawiająceUkrywanie informacji w GoPowtórka – dane studentów10Typy generyczne (Go 1.18+)
Wprowadzenie do typów generycznychParametry typówOgraniczenia typówStruktury generyczneObejście ograniczeń metod generycznychPodsumowanie — generyczna kolekcja2Typy i struktury w praktyce
Typy proste i złożoneDefiniowanie własnych typówTagi pól strukturStruktury anonimoweStruktury zagnieżdżoneWartości zerowe i domyślnePodsumowanie – książka kontaktów5Kompozycja zamiast dziedziczenia
Dlaczego Go nie ma dziedziczeniaPodstawy osadzania strukturPromowanie metodOsadzanie wielu strukturOsadzanie a agregacjaPrzesłanianie osadzonych metodPodsumowanie — hierarchia pracowników8Obsługa błędów i programowanie obiektowe
Interfejs błęduWłasne typy błędówOpakowywanie błędów (fmt.Errorf)Błędy wartowniczeerrors.Is() i errors.As()Panic, Defer i RecoverPodsumowanie — parser plików3Wskaźniki i pamięć
Podstawy wskaźników w GoWskaźniki do strukturPrzekazywanie przez wartość a przez referencjęFunkcja new()Odśmiecanie pamięci w GoPowtórka — kreator listy wiązanej6Polimorfizm w Go
Polimorfizm za pomocą interfejsówDuck typing w GoZasady spełniania interfejsówKolekcje polimorficzneWstrzykiwanie zależnościPowtórka — procesor płatności9Współbieżność i OOP
Podstawy goroutinesKanały i komunikacjaKanały buforowane i niebuforowaneInstrukcja selectsync.Mutex i sync.RWMutexsync.WaitGroupProjektowanie struktur bezpiecznych wątkowoPowtórka – pula workerów12Zaawansowane zagadnienia programowania obiektowego
Wzorzec opcji funkcyjnychWzorzec Builder w GoŁańcuchowe wywoływanie metodAliasy typów a definicje typówPodstawy refleksjiPrzegląd generowania koduPoćwicz samodzielnie: Kompilator Go online