Menu
Coddy logo textTech

Patrón Builder en Go

Parte de la sección Programación Orientada a Objetos del Journey de GO de Coddy. Lección 80 de 107.

El patrón Builder separa la construcción de un objeto complejo de su representación. A diferencia del patrón de Opciones Funcionales, Builder utiliza una estructura de construcción dedicada con métodos que configuran el objeto paso a paso.

A continuación, se muestra cómo implementar un builder para una solicitud 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
}

Cada método devuelve el puntero del constructor, lo que permite encadenar métodos. El método Build() finaliza y devuelve el objeto construido:

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

El patrón Builder destaca cuando los objetos requieren varios pasos de configuración o cuando quieres imponer una secuencia de construcción específica. Es especialmente útil para crear objetos inmutables o cuando el propio proceso de construcción necesita validación.

challenge icon

Desafío

Fácil

¡Construyamos un compositor de mensajes de correo electrónico usando el patrón Builder! Los mensajes de correo electrónico tienen muchos componentes opcionales, como destinatarios, CC, asunto, cuerpo y archivos adjuntos, lo que los convierte en candidatos perfectos para una construcción paso a paso mediante el encadenamiento de métodos.

Organizarás tu código en dos archivos:

  • email.go: Define la estructura de tu correo electrónico y su builder.

    Crea una estructura Email con estos campos:

    • from (string)
    • to (slice de strings)
    • cc (slice de strings)
    • subject (string)
    • body (string)

    Crea una estructura EmailBuilder que contenga un puntero a un Email en construcción. Implementa NewEmailBuilder(), que devuelva un builder nuevo con un Email inicializado (slices vacíos para to y cc).

    Añade estos métodos del builder, cada uno devolviendo *EmailBuilder para permitir el encadenamiento:

    • From(address string) - establece el remitente
    • To(address string) - añade un destinatario al slice to
    • CC(address string) - añade un destinatario al slice cc
    • Subject(subject string) - establece el asunto
    • Body(body string) - establece el cuerpo del correo electrónico

    Añade un método Build() que devuelva el *Email construido.

    Finalmente, añade un método Summary() en Email que devuelva una cadena con este formato:

    From: [from]
    To: [comma-separated to addresses]
    CC: [comma-separated cc addresses or "none"]
    Subject: [subject]
    Body: [body]
  • main.go: Construye y muestra mensajes de correo electrónico usando el builder.

    Lee la dirección del remitente, después lee la cantidad de destinatarios y cada dirección de destinatario. A continuación, lee la cantidad de destinatarios en CC y cada dirección de CC. Finalmente, lee el asunto y el cuerpo.

    Usa EmailBuilder con el encadenamiento de métodos para construir el correo electrónico y, después, imprime su resumen.

Se proporcionarán las siguientes entradas:

  • Línea 1: Dirección del remitente
  • Línea 2: Número de destinatarios
  • Líneas siguientes: Cada dirección de destinatario
  • Línea siguiente: Número de destinatarios en CC
  • Líneas siguientes: Cada dirección de CC
  • Línea siguiente: Asunto
  • Línea final: Cuerpo

Por ejemplo, dada la siguiente entrada:

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

Tu salida debería ser:

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.

Y dada la siguiente entrada:

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

Tu salida debería ser:

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

Observa cómo el builder te permite añadir varios destinatarios de uno en uno mediante llamadas repetidas a To(), y cómo el patrón mantiene el proceso de construcción limpio y legible incluso con muchos campos opcionales.

Pruébalo tú mismo

package main

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

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

	// Leer la dirección del remitente
	from, _ := reader.ReadString('\n')
	from = strings.TrimSpace(from)

	// Leer el número de destinatarios
	toCountStr, _ := reader.ReadString('\n')
	toCount, _ := strconv.Atoi(strings.TrimSpace(toCountStr))

	// Leer cada dirección de destinatario
	toAddresses := make([]string, toCount)
	for i := 0; i < toCount; i++ {
		addr, _ := reader.ReadString('\n')
		toAddresses[i] = strings.TrimSpace(addr)
	}

	// Leer el número de destinatarios en CC
	ccCountStr, _ := reader.ReadString('\n')
	ccCount, _ := strconv.Atoi(strings.TrimSpace(ccCountStr))

	// Leer cada dirección de CC
	ccAddresses := make([]string, ccCount)
	for i := 0; i < ccCount; i++ {
		addr, _ := reader.ReadString('\n')
		ccAddresses[i] = strings.TrimSpace(addr)
	}

	// Leer el asunto
	subject, _ := reader.ReadString('\n')
	subject = strings.TrimSpace(subject)

	// Leer el cuerpo
	body, _ := reader.ReadString('\n')
	body = strings.TrimSpace(body)

	// TODO: Usa el EmailBuilder con encadenamiento de métodos para construir el email
	// Empieza con NewEmailBuilder(), luego encadena From(), To(), CC(), Subject(), Body()
	// Finalmente llama a Build() para obtener el Email

	// TODO: Imprime el resumen del email usando el método Summary()
}
quiz iconPonte a prueba

Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.

Todas las lecciones de Programación Orientada a Objetos

Practica por tu cuenta: Compilador de Go online