Pattern Builder in Go
Fa parte della sezione Programmazione orientata agli oggetti del percorso GO di Coddy. Lezione 80 di 107.
Il Builder Pattern separa la costruzione di un oggetto complesso dalla sua rappresentazione. A differenza del pattern Functional Options, il Builder usa una struct builder dedicata con metodi che configurano l’oggetto passo dopo passo.
Ecco come implementare un builder per una richiesta 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
}Ogni metodo restituisce il puntatore al builder, consentendo di concatenare i metodi. Il metodo Build() finalizza e restituisce l'oggetto costruito:
req := NewRequestBuilder().
Method("POST").
URL("https://api.example.com").
Header("Content-Type", "application/json").
Build()Il pattern Builder è particolarmente adatto quando gli oggetti richiedono più passaggi di configurazione o quando vuoi imporre una sequenza di costruzione specifica. È particolarmente utile per creare oggetti immutabili o quando il processo di costruzione stesso deve essere convalidato.
Sfida
FacileCreiamo un compositore di messaggi email usando il pattern Builder! I messaggi email hanno molti componenti opzionali, come destinatari, CC, oggetto, corpo e allegati, il che li rende perfetti per essere costruiti passo dopo passo concatenando i metodi.
Organizzerai il codice in due file:
email.go: definisci la struttura dell'email e il relativo builder.Crea una struct
Emailcon questi campi:from(string)to(slice di stringhe)cc(slice di stringhe)subject(string)body(string)
Crea una struct
EmailBuilderche contiene un puntatore a un'Email in fase di costruzione. ImplementaNewEmailBuilder(), che restituisce un nuovo builder con un'Email inizializzata (slice vuote pertoecc).Aggiungi questi metodi del builder, ognuno dei quali restituisce
*EmailBuilderper consentire la concatenazione:From(address string)- imposta il mittenteTo(address string)- aggiunge un destinatario alla slicetoCC(address string)- aggiunge un destinatario alla sliceccSubject(subject string)- imposta l'oggettoBody(body string)- imposta il corpo dell'email
Aggiungi un metodo
Build()che restituisce la*Emailcostruita.Infine, aggiungi un metodo
Summary()su Email che restituisce una stringa in questo formato:From: [from] To: [comma-separated to addresses] CC: [comma-separated cc addresses or "none"] Subject: [subject] Body: [body]main.go: crea e visualizza messaggi email usando il builder.Leggi l'indirizzo del mittente, poi leggi il numero di destinatari e l'indirizzo di ciascun destinatario. Poi, leggi il numero di destinatari in CC e ciascun indirizzo CC. Infine, leggi l'oggetto e il corpo.
Usa EmailBuilder concatenando i metodi per costruire l'email, quindi stampa il riepilogo.
Verranno forniti i seguenti input:
- Riga 1: indirizzo del mittente
- Riga 2: numero di destinatari
- Righe successive: indirizzo di ciascun destinatario
- Riga successiva: numero di destinatari in CC
- Righe successive: indirizzo di ciascun destinatario in CC
- Riga successiva: oggetto
- Riga finale: corpo
Ad esempio, dato:
alice@company.com
2
bob@company.com
carol@company.com
1
manager@company.com
Weekly Report
Please find the weekly report attached.L'output dovrebbe essere:
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.E dato:
support@service.com
1
customer@email.com
0
Your Ticket Update
Your support ticket has been resolved.L'output dovrebbe essere:
From: support@service.com
To: customer@email.com
CC: none
Subject: Your Ticket Update
Body: Your support ticket has been resolved.Nota come il builder ti consenta di aggiungere più destinatari uno alla volta con chiamate ripetute a To() e come il pattern mantenga il processo di costruzione chiaro e leggibile anche in presenza di molti campi opzionali.
Provalo tu
package main
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
)
func main() {
reader := bufio.NewReader(os.Stdin)
// Leggi l'indirizzo del mittente
from, _ := reader.ReadString('\n')
from = strings.TrimSpace(from)
// Leggi il numero di destinatari
toCountStr, _ := reader.ReadString('\n')
toCount, _ := strconv.Atoi(strings.TrimSpace(toCountStr))
// Leggi l'indirizzo di ogni destinatario
toAddresses := make([]string, toCount)
for i := 0; i < toCount; i++ {
addr, _ := reader.ReadString('\n')
toAddresses[i] = strings.TrimSpace(addr)
}
// Leggi il numero di destinatari CC
ccCountStr, _ := reader.ReadString('\n')
ccCount, _ := strconv.Atoi(strings.TrimSpace(ccCountStr))
// Leggi ogni indirizzo CC
ccAddresses := make([]string, ccCount)
for i := 0; i < ccCount; i++ {
addr, _ := reader.ReadString('\n')
ccAddresses[i] = strings.TrimSpace(addr)
}
// Leggi l'oggetto
subject, _ := reader.ReadString('\n')
subject = strings.TrimSpace(subject)
// Leggi il corpo del messaggio
body, _ := reader.ReadString('\n')
body = strings.TrimSpace(body)
// TODO: Usa EmailBuilder con chiamate ai metodi concatenate per costruire l'email
// Inizia con NewEmailBuilder(), poi concatena From(), To(), CC(), Subject(), Body()
// Infine chiama Build() per ottenere l'Email
// TODO: Stampa il riepilogo dell'email usando il metodo Summary()
}
Questa lezione include un breve quiz. Inizia la lezione per rispondere e tenere traccia dei tuoi progressi.
Tutte le lezioni di Programmazione orientata agli oggetti
1Fondamenti di OOP in Go
File esterniWorkspace e moduli GoPacchetti e importazioniNomi esportati e non esportatiIntroduzione all’OOP in GoGli struct come classiDefinire metodi sugli structReceiver con puntatore vs receiver con valoreInizializzazione degli structFunzioni costruttriciRiepilogo - Calcolatrice semplice4Interfacce
Introduzione alle interfacceImplementazione implicitaL’interfaccia come contrattoInterfaccia vuota (any)Asserzione di tipoSwitch sul tipoComposizione di interfacceInterfacce Stringer ed ErrorRipasso - Calcolatore di forme7Incapsulamento
Campi esportati e non esportatiIncapsulamento a livello di packageMetodi Getter e SetterNascondimento delle informazioni in GoRiepilogo - Registri degli studenti10Tipi generici (Go 1.18+)
Introduzione ai tipi genericiParametri di tipoVincoli di tipoStruct genericheSoluzione alternativa per i metodi genericiRiepilogo - Collezione generica13Modelli di progettazione Parte 1
Introduzione ai modelli di progettazioneModello SingletonModello FactoryModello Abstract FactoryModello ObserverModello Strategy2Approfondimento su tipi e struct
Tipi di base e compostiDefinizioni di tipi personalizzatiTag delle structStruct anonimeStruct annidateValori zero e predefinitiRipasso - Rubrica5Composizione invece dell'ereditarietà
Perché Go non ha l'ereditarietàFondamenti dell'embedding delle structPromozione dei metodiEmbedding di più structEmbedding e aggregazione a confrontoMascheramento dei metodi embeddedRiepilogo: gerarchia dei dipendenti8Gestione degli errori e OOP
L'interfaccia errorTipi di errore personalizzatiWrapping degli errori (fmt.Errorf)Errori sentinellaerrors.Is() ed errors.As()Panic, Defer e RecoverRiepilogo - Parser di file11Libreria standard e OOP
io.Reader e io.Writersort.InterfaceInterfaccia fmt.Stringerencoding/json con le structInterfaccia http.HandlerRipasso - modelli REST API14Modelli di progettazione – Parte 2
Pattern CommandPattern AdapterPattern DecoratorPattern Template MethodPattern StatePattern CompositeMiddleware come Decorator3Puntatori e memoria
Concetti base dei puntatori in GoPuntatori a structPassaggio per valore vs per riferimentoLa funzione new()Garbage collection in GoRiepilogo - Costruttore di liste concatenate6Polimorfismo in Go
Polimorfismo tramite interfacceDuck typing in GoRegole di soddisfacimento delle interfacceCollezioni polimorficheIniezione delle dipendenzeRiepilogo - Elaboratore di pagamenti9Concorrenza e OOP
Basi delle goroutineCanali e comunicazioneCanali bufferizzati vs non bufferizzatiIstruzione selectsync.Mutex e sync.RWMutexsync.WaitGroupProgettazione di struct thread-safeRiepilogo: worker pool12Concetti avanzati di OOP
Pattern delle opzioni funzionaliPattern Builder in GoConcatenamento dei metodiAlias di tipo e definizioni a confrontoNozioni di base sulla reflectionPanoramica sulla generazione del codiceEsercitati da solo: Compilatore Go online