Menu
CoddyTech

Mẫu Builder trong Go

Thuộc phần Lập trình hướng đối tượng trong hành trình GO của Coddy. Bài học 80 trên 107.

Mẫu Builder tách việc tạo một đối tượng phức tạp khỏi cách biểu diễn đối tượng đó. Khác với mẫu Functional Options, Builder dùng một cấu trúc builder riêng với các phương thức cấu hình đối tượng từng bước.

Dưới đây là cách triển khai một trình dựng cho yêu cầu 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
}

Mỗi phương thức trả về con trỏ đến builder, cho phép bạn gọi nối tiếp các phương thức. Phương thức Build() hoàn tất quá trình xây dựng và trả về đối tượng đã tạo:

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

Mẫu Builder phù hợp khi đối tượng cần trải qua nhiều bước cấu hình hoặc khi bạn muốn buộc quy trình khởi tạo tuân theo một trình tự cụ thể. Mẫu này đặc biệt hữu ích khi tạo đối tượng bất biến hoặc khi cần xác thực chính quy trình khởi tạo.

challenge icon

Thử thách

Dễ

Hãy cùng tạo trình soạn email bằng Mẫu Builder nhé! Email có nhiều thành phần tùy chọn như người nhận, CC, chủ đề, nội dung và tệp đính kèm, nên rất phù hợp để tạo từng bước bằng cách nối chuỗi phương thức.

Bạn sẽ sắp xếp code trong hai tệp:

  • email.go: Định nghĩa cấu trúc email và trình tạo.
  • Tạo một cấu trúc Email với các trường sau:

    • from (chuỗi)
    • to (slice các chuỗi)
    • cc (slice các chuỗi)
    • subject (chuỗi)
    • body (chuỗi)

    Tạo cấu trúc EmailBuilder chứa con trỏ đến một Email đang được tạo. Triển khai NewEmailBuilder() để trả về một trình tạo mới có Email đã khởi tạo (các slice to và cc rỗng).

    Thêm các phương thức của trình tạo sau, mỗi phương thức trả về *EmailBuilder để nối chuỗi:

    • From(address string) - đặt địa chỉ người gửi
    • To(address string) - thêm người nhận vào slice to
    • CC(address string) - thêm người nhận vào slice cc
    • Subject(subject string) - đặt dòng chủ đề
    • Body(body string) - đặt nội dung email

    Thêm phương thức Build() để trả về *Email đã tạo.

    Cuối cùng, thêm phương thức Summary() vào Email để trả về một chuỗi theo định dạng sau:

    From: [from]
    To: [comma-separated to addresses]
    CC: [comma-separated cc addresses or "none"]
    Subject: [subject]
    Body: [body]
  • main.go: Tạo và hiển thị email bằng trình tạo.

    Đọc địa chỉ người gửi, sau đó đọc số lượng người nhận và địa chỉ của từng người. Tiếp theo, đọc số lượng người nhận CC và địa chỉ của từng người. Cuối cùng, đọc chủ đề và nội dung.

    Dùng EmailBuilder cùng cách nối chuỗi phương thức để tạo email, rồi in phần tóm tắt.

Đầu vào sẽ có dạng như sau:

  • Dòng 1: Địa chỉ người gửi
  • Dòng 2: Số lượng người nhận
  • Các dòng tiếp theo: Địa chỉ của từng người nhận
  • Dòng tiếp theo: Số lượng người nhận CC
  • Các dòng tiếp theo: Địa chỉ của từng người nhận CC
  • Dòng tiếp theo: Chủ đề
  • Dòng cuối: Nội dung

Ví dụ, với đầu vào:

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

Đầu ra của bạn sẽ là:

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.

Với đầu vào:

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

Đầu ra của bạn sẽ là:

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

Hãy chú ý cách trình tạo cho phép bạn thêm nhiều người nhận, từng người một, thông qua các lần gọi To(), và cách mẫu này giúp quy trình tạo luôn gọn gàng, dễ đọc ngay cả khi có nhiều trường tùy chọn.

Tự làm thử

package main

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

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

	// Đọc địa chỉ người gửi
	from, _ := reader.ReadString('\n')
	from = strings.TrimSpace(from)

	// Đọc số lượng người nhận
	toCountStr, _ := reader.ReadString('\n')
	toCount, _ := strconv.Atoi(strings.TrimSpace(toCountStr))

	// Đọc địa chỉ của từng người nhận
	toAddresses := make([]string, toCount)
	for i := 0; i < toCount; i++ {
		addr, _ := reader.ReadString('\n')
		toAddresses[i] = strings.TrimSpace(addr)
	}

	// Đọc số lượng người nhận CC
	ccCountStr, _ := reader.ReadString('\n')
	ccCount, _ := strconv.Atoi(strings.TrimSpace(ccCountStr))

	// Đọc từng địa chỉ CC
	ccAddresses := make([]string, ccCount)
	for i := 0; i < ccCount; i++ {
		addr, _ := reader.ReadString('\n')
		ccAddresses[i] = strings.TrimSpace(addr)
	}

	// Đọc tiêu đề
	subject, _ := reader.ReadString('\n')
	subject = strings.TrimSpace(subject)

	// Đọc nội dung
	body, _ := reader.ReadString('\n')
	body = strings.TrimSpace(body)

	// TODO: Dùng EmailBuilder và chuỗi phương thức (method) để tạo email
	// Bắt đầu với NewEmailBuilder(), rồi gọi nối tiếp From(), To(), CC(), Subject(), Body()
	// Cuối cùng, gọi Build() để lấy Email

	// TODO: In ra bản tóm tắt email bằng phương thức Summary()
}
quiz iconTự kiểm tra

Bài học này có một bài trắc nghiệm ngắn. Bắt đầu bài học để trả lời và theo dõi tiến độ.

Tất cả bài học trong Lập trình hướng đối tượng

Tự luyện tập: Trình biên dịch Go online