Design Pattern Series - Factory Pattern (Golang)

Programing 25 Th05 2025

Factory Pattern là gì?

Factory Pattern là một design pattern thuộc nhóm Creational Patterns. Nó cung cấp cách để tạo đối tượng mà không cần chỉ định trực tiếp class cụ thể. Thay vào đó, Factory Pattern sử dụng factory method hoặc factory struct để xác định loại đối tượng cần tạo dựa trên tham số đầu vào hoặc điều kiện.

Trong Go, do không hỗ trợ kế thừa như các ngôn ngữ hướng đối tượng truyền thống, Factory Pattern thường được triển khai bằng functions hoặc structs, kết hợp với interface để đảm bảo tính linh hoạt và trừu tượng.

Mục đích của Factory Pattern

  • Trừu tượng hóa việc tạo đối tượng: Giấu đi logic tạo object, giúp code dễ bảo trì và mở rộng.
  • Tăng tính linh hoạt: Cho phép thêm object type mới mà không cần sửa code hiện có (Open/Closed Principle).
  • Kiểm soát tập trung: Logic tạo object nằm ở một chỗ, dễ quản lý và tối ưu.
  • Giảm phụ thuộc: Code phía client chỉ làm việc với interface hoặc abstract type, không cần biết chi tiết implement cụ thể.

Khi nào dùng Factory Pattern?

  • Khi cần tạo nhiều object khác nhau có chung một interface.
  • Khi logic tạo object phức tạp (ví dụ: khởi tạo với config mặc định hoặc giá trị đặc biệt).
  • Khi muốn tách biệt logic tạo object khỏi logic sử dụng object.

Ví dụ thực tế

  • Kết nối cơ sở dữ liệu: Tạo connection khác nhau (MySQL, PostgreSQL, SQLite) dựa trên config.
  • Xử lý thanh toán: Quản lý nhiều phương thức thanh toán (CreditCard, PayPal) trong hệ thống e-commerce.

Triển khai Factory Pattern trong Go

Giả sử ta có một hệ thống thanh toán hỗ trợ hai loại: CreditCardPayPal. Mỗi loại đều có method chung là Pay. Ta sẽ dùng Factory Pattern để tạo object phù hợp dựa trên loại thanh toán được yêu cầu.

Bước 1: Định nghĩa Interface

type PaymentMethod interface {
    Pay(amount float64) string
}

Tất cả các phương thức thanh toán phải implement method Pay.

Bước 2: Tạo các Struct cụ thể

type CreditCardPayment struct{}

func (c *CreditCardPayment) Pay(amount float64) string {
    return fmt.Sprintf("Paid %.2f using Credit Card", amount)
}

type PayPalPayment struct{}

func (p *PayPalPayment) Pay(amount float64) string {
    return fmt.Sprintf("Paid %.2f using PayPal", amount)
}

Bước 3: Tạo Factory function

func PaymentMethodFactory(paymentType string) (PaymentMethod, error) {
    switch paymentType {
    case "creditcard":
        return &CreditCardPayment{}, nil
    case "paypal":
        return &PayPalPayment{}, nil
    default:
        return nil, fmt.Errorf("unsupported payment method: %s", paymentType)
    }
}

Bước 4: Sử dụng Factory trong client code

func main() {
    // Credit Card
    creditCard, err := PaymentMethodFactory("creditcard")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println(creditCard.Pay(100.50))

    // PayPal
    payPal, err := PaymentMethodFactory("paypal")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println(payPal.Pay(75.25))

    // Phương thức không hỗ trợ
    _, err = PaymentMethodFactory("bitcoin")
    if err != nil {
        fmt.Println(err)
    }
}

Giải thích từng bước

  • Bước 1: Interface PaymentMethod giúp trừu tượng hóa, client chỉ cần làm việc với interface thay vì implementation cụ thể.
  • Bước 2: Các struct CreditCardPayment, PayPalPayment implement method Pay.
  • Bước 3: PaymentMethodFactory tập trung toàn bộ logic tạo object.
  • Bước 4: Client chỉ cần gọi factory, không quan tâm object được tạo thế nào.

Full code

package main

import (
    "fmt"
    "log"
)

// Định nghĩa interface
type PaymentMethod interface {
    Pay(amount float64) string
}

// Implement CreditCardPayment
type CreditCardPayment struct{}

func (c *CreditCardPayment) Pay(amount float64) string {
    return fmt.Sprintf("Paid %.2f using Credit Card", amount)
}

// Implement PayPalPayment
type PayPalPayment struct{}

func (p *PayPalPayment) Pay(amount float64) string {
    return fmt.Sprintf("Paid %.2f using PayPal", amount)
}

// Factory function
func PaymentMethodFactory(paymentType string) (PaymentMethod, error) {
    switch paymentType {
    case "creditcard":
        return &CreditCardPayment{}, nil
    case "paypal":
        return &PayPalPayment{}, nil
    default:
        return nil, fmt.Errorf("unsupported payment method: %s", paymentType)
    }
}

func main() {
    creditCard, err := PaymentMethodFactory("creditcard")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println(creditCard.Pay(100.50))

    payPal, err := PaymentMethodFactory("paypal")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println(payPal.Pay(75.25))

    _, err = PaymentMethodFactory("bitcoin")
    if err != nil {
        fmt.Println(err)
    }
}

Output

Paid 100.50 using Credit Card
Paid 75.25 using PayPal
unsupported payment method: bitcoin

Kết luận

Factory Pattern là công cụ mạnh mẽ để quản lý việc tạo object trong Go, đặc biệt khi cần hỗ trợ nhiều loại object có chung một interface. Nó giúp code dễ mở rộng, dễ bảo trì, và tuân theo nguyên tắc thiết kế hướng đối tượng.

Có thể mở rộng ví dụ này bằng cách:

  • Thêm phương thức thanh toán mới (BankTransfer, Crypto).
  • Thêm logic khởi tạo phức tạp hơn trong factory.
  • Sử dụng config hoặc tham số để tùy chỉnh object được tạo.

Bài tiếp theo trong series Abstract Factory Pattern

Chuyên mục