Sử dụng Closure và Dependency Injection trong Golang

Trong lập trình Go, bạn có thể đã từng gặp tình huống muốn truyền một biến cấu hình (config), hoặc đối tượng kết nối CSDL (database), vào một hàm nhưng không thể làm trực tiếp vì hàm đó cần đúng một định dạng.

Giải pháp? Closure kết hợp với Dependency Injection.

Bài viết này sẽ giúp bạn hiểu rõ cách sử dụng kỹ thuật này bằng ví dụ đơn giản, dễ hiểu, không gắn với bất kỳ framework nào.


🎯 Vấn đề thường gặp

func Greet(name string) {
    fmt.Println("Hello", name)
}

Bây giờ bạn muốn thêm một cấu hình prefix để tùy biến lời chào, ví dụ: "👋 Xin chào" hoặc "Hello".

Bạn không muốn viết lại logic mỗi lần, mà muốn truyền prefix từ bên ngoài. Nhưng Greet() lại chỉ chấp nhận name.


🛠 Cách dùng Closure để truyền thêm biến

Bước 1: Tạo Closure có chứa prefix

func MakeGreeter(prefix string) func(name string) {
    return func(name string) {
        fmt.Printf("%s %s\n", prefix, name)
    }
}

Bước 2: Sử dụng Closure như một hàm thông thường

func main() {
    greeter := MakeGreeter("👋 Xin chào")
    greeter("Nguyễn Văn A")

    another := MakeGreeter("Hello")
    another("John")
}

Kết quả:

👋 Xin chào Nguyễn Văn A
Hello John

📌 Giải thích

  • MakeGreeter là một hàm tạo ra một hàm khác (closure).
  • Closure có thể “nhớ” giá trị prefix khi nó được tạo.
  • Logic xử lý vẫn giống nhau, nhưng dễ tái sử dụng với các cấu hình khác nhau.

🌐 Ứng dụng thực tế với HTTP Server

func NewHelloHandler(greeting string) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
        name := r.URL.Query().Get("name")
        fmt.Fprintf(w, "%s %s", greeting, name)
    }
}

func main() {
    http.HandleFunc("/hello", NewHelloHandler("Xin chào"))
    log.Fatal(http.ListenAndServe(":8080", nil))
}

Khi người dùng truy cập: http://localhost:8080/hello?name=Nam ⇒ Kết quả:

Xin chào Nam

🔚 Kết luận

Closure trong Go không chỉ là một tính năng của ngôn ngữ — nó là công cụ mạnh mẽ để bạn quản lý phụ thuộc linh hoạt mà vẫn giữ cho mã gọn gàng, dễ mở rộng.

Bạn hoàn toàn có thể áp dụng kỹ thuật này vào bất kỳ chức năng nào như cấu hình, logger, dịch vụ kết nối cơ sở dữ liệu, hoặc handler trong web API.

Nếu bạn muốn xem thêm ví dụ chuyên sâu hơn (gắn với database, bot, hay context), hãy để lại bình luận nhé!

Leave a Comment