+9

Golang Design Patterns - Singleton. Pattern mà mọi lập trình viên đều biết đến

I. Singleton - Creational Pattern

  • Singleton không còn quá xa lạ với lập trình viên, là mẫu thiết kế mà mọi người đều nhớ đến đầu tiên khi nhắc về design patterns. Gần như 80% câu hỏi của lập trình viên đều dành cho Singleton khi đặt vấn đề về Design Patterns.
  • Đúng theo tên gọi của nó, Singleton là một instance duy nhất của một loại đối tượng, chắc chắn không tồn tại đối tượng thứ hai như vậy trong toàn bộ chương trình của chúng ta. Tại lần đầu tiên được gọi, instance sẽ được khởi tạo và được reuse cho tất cả các lần sử dụng tiếp theo trong chương trình.

II. Khi nào nên sử dụng Singleton?

Vậy thì khi nào chúng ta nên sử dụng Singleton, mình sẽ liệt kê một vài trường hợp sau mà chúng ta thường sử dụng Singleton nhé:

  • Khi chúng ta muốn tận dụng một connection duy nhất xuống database cho từng query khác nhau.
  • Khi cần mở một Secure Shell (SSH) kết nối đến server để làm một số công việc, và chúng ta không muốn reopen connection này khi làm từng công việc đó.
  • Chúng ta cần giới hạn số lượng truy cập đến một biến, hay một vùng nhớ, khi đó Singleton đóng vai trò như một (những) con đường mà chúng ta giới hạn số lượng truy cập đồng thời (thường được biết đến là Connection Pool Design Pattern). Với Golang, chúng ta có thể sử dụng channels để handle việc này.

Còn rất tính ứng dụng của mẫu Singleton, mình chỉ liệt kê một vài thứ phía trên thôi ^^.

III. Ví dụ thực tế

  • Chúng ta có 1 function Print được thực thi khi user click button In đơn hàng và một đối tượng Counter để ghi lại số lần Click của User trong suốt lifetime. Khi đó ta phải luôn đảm bảo rằng đối tượng Counter luôn là duy nhất, khi đó Singleton sẽ hữu dụng với chúng ta (tuy nhiên vẫn còn nhiều cách không sử dụng Singleton vẫn có thể làm được, nhưng có lẽ sẽ messy hơn 😄) image.png
*User không biết được đối tượng Counter luôn là duy nhất sau những lần Print (những lần open the door khác nhau). Nguồn: Guru*
  • Để hoạt động một cách đúng đắn, đối tượng Counter ở trên cần tuân thủ những nguyên tắc sau:
    1. Khi chưa có đối tượng Counter nào được khởi tạo trước đó, Couter sẽ được khởi tạo với initial value là 0.
    2. Trong trường hợp Counter đã được khởi tạo từ trước, trả về instance Counter đó.
    3. Nếu chúng ta trigger phương thức Print, count value của Counter được tăng thêm 1.

IV. Implementation

Mình sẽ tạo một chương trình đơn giản để implement Singleton Counter trong ví dụ trên, bắt đầu với project structure như sau: image.png

  • File main.go (entry point)
  • Package Singleton: implement coutner singleton
  • File go.mod

Đoạn code cũng ngắn, nên mình sẽ share toàn bộ source ở ảnh bên dưới nhé: image.png

  • Ở file counter.go, chúng ta define một private struct là singleton bao gồm field counter kiểu int. Struct singleton bao gồm 2 method Increase và Get.
  • Vì là private struct, nên chúng ta không thể truy cập/khởi tạo trực tiếp đối tượng singleton này từ bên ngoài được, mà phải thông qua public function GetInstance, function này có nhiệm vụ kiểm tra instance singleton đã được khai báo từ trước chưa. Nếu chưa thì sẽ khởi tạo đối tượng mới, ngược lại thì trả về đối tượng hiện tại.
  • Qua file main.go ở đây mình có note một vài comments. Hiểu đơn thuần là khi muốn tăng giá trị biến counter hay get value từ nó, chúng ta phải thông qua GetInstance, điều này đảm bảo cho chúng ta luôn sử dụng đúng đối tượng Singleton duy nhất trong toàn bộ chương trình.
  • Run chương trình bằng câu lệnh: go run main.go và kết quả cho ta: image.png

V. Lời kết

Trên đây mình đã giải thích cho các bạn hiểu về Singleton, mẫu Design Pattern thông dụng nhất đối với developers. Counter ở trên chỉ là một ví dụ nho nhỏ, đối với các chương trình lớn, phức tạp hơn, việc khởi tạo một đối tượng đôi khi sẽ trải qua một quá trình tính toán phức tạp, hay tiêu tốn nhiều tài nguyên và thời gian, chúng ta sẽ thấy được tầm quan trọng của Singleton một cách rõ ràng hơn.
Ở bài viết này mình chỉ giới hạn ở mực basic nhất cách triển khai Singleton trong Golang, còn có rất nhiều vấn đề phải quan tâm khi implement Singleton, chẳng hạn như Not Thread Safe hay Thread Safe. Hi vọng sẽ gặp các bạn ở các chapters sau.


Cảm ơn các bạn đã đọc ^^

Source code: https://github.com/khaaleoo/golang-design-patterns

VI. References

  • Go Design Patterns (Mario Castro Contreras)
  • Guru

All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí