Singleton design pattern (ok)
https://phambinh.net/bai-viet/singleton-design-pattern
Singleton là một design pattern thuộc nhóm khởi tạo, với design pattern này thì mỗi class sẽ chỉ khởi tạo được một đối tượng duy nhất.
Mục lục
I. BÀI TOÁN
Mình đang xây dựng một website tin tức sử dụng PHP và MySQL. Để quản lý việc kết nối giữa PHP và MySQL, mình có tạo ra một class Database
như sau:
Cách sử dụng
Ok, cùng review đoạn code trên xem thế nào nhé:
Class
Database
có một thuộc tính public là$connection
, và thuộc tính này là “thể hiển” của classmysqli
(dòng 11 – file Database.php).Thuộc tính
$connection
chính là cầu nối giữa PHP và MySQL, nếu bạn muốn thực hiện bất kỳ query nào từ website PHP tới MySQL, thì đều phải sử dụng tới thuộc tính$connection
này.Cách sử dụng thì bạn thấy rồi đó, mình khởi tạo class
Database
như bình thường, sau đó sử dụng thuộc tính$connection
để thực hiện một query đơn giản
Tới lúc này, mọi thứ vẫn ổn, ngoại trừ việc mình đã cố tình loại bỏ các thao tác bắt lỗi để đoạn code trở nên đơn giản, dễ hiểu hơn.
Nhưng giờ bài toán của mình trở nên phức tạp hơn, trong quá trình tải trang web, có rất nhiều chỗ mình cần sử dụng đến thông tin trong database. Cụ thể như 2 trường hợp sau:
Sử dụng lần 1 ở mywebsite/init.php
, mục đích để lấy các thông tin cơ bản của website như tiêu đề trang web, mô tả của trang web, nằm trong bảng settings
.
Sử dụng lần 2 ở mywebsite/home.php
, mục đích để lấy ra các bài viết mới nằm trong bảng articles
.
Giờ chúng ta nhìn lại code của 2 file trên, chúng bắt đầu có một số vấn đề:
Code bị lặp đi lặp lại
Nếu 2 file trên chạy tuần tự, thì bạn sẽ có 2 connection được khởi tạo.
Vấn đề code bị lặp đi lặp lại tạm thời chúng ta chưa bàn tới, hãy bàn tới việc bạn sẽ có 2 connection được tạo ra đã:
Lần 1 tạo ở
mywebsite/init.php
dòng 9.Lần 2 tạo ở
mywebsite/home.php
dòng 9.
Việc tạo ra 2 connection này rõ là không nên, bởi:
Càng nhiều connection, máy bạn sẽ càng tốn tài nguyên, đồng nghĩa với hiệu năng (tốc độ tải trang web) kém.
Hai connection được tạo ra giống hệt nhau, mục đích tạo ra cũng giống nhau, vậy tại sao phải tạo ra 2 connection, kể như chỉ cần tạo ra 1 cái rồi dùng chung cho tất cả có phải tốt hơn không?
Trên là mình mới lấy ví dụ cần sử dụng dữ liệu trong MySQL ở 2 chỗ, còn trong thực tế nó xảy ra vô cùng thường xuyên. Nếu cứ áp dụng cách như trên, trong một lần tải trang web khả năng bạn sẽ phải tạo ra hằng trăm connection.
Có cách nào để khắc phục điều này, làm sao để xuyên suốt quá trình hoạt động của website chỉ tạo ra một connection duy nhất. Singleton design pattern chính là thứ bạn cần lúc này.
II. GIẢI PHÁP VỚI SINGLETON DESIGN PATTERN
Singleton design pattern là một dạng design pattern thuộc nhóm khởi tạo, nó giúp bạn với mỗi class sẽ chỉ có thể tạo ra một đối tượng.
Singleton cũng được biết đến như một trong những design pattern được sử dụng nhiều nhất.
Quay trở lại ví dụ với class Database
ở phần I, giờ mình sẽ viết lại theo singleton desing pattern.
Cách sử dụng
Các thay đổi so với phiên bản trước đó như sau:
Có một thuộc tính
private static
là$instance
Hàm
__construct()
chuyển từ public sangprivate
Bổ sung thêm một hàm mới là
public static function getInstance
Khi sử dụng, thay vì gọi toán tử new để khởi tạo đối tượng thì sử dụng phương thức
Database::getInstance()
.
Cùng review đoạn code trên xem có gì cải tiến không nhé:
Vì hàm
__construct()
ở dạngprivate
, nên bạn sẽ không thể sử dụng từ khóanew
để khởi tạo đối tượng từ bên ngoài class, giúp hạn chế việc khởi tạo đối tượng một cách bừa bãi.getInstance()
là một phương thứcstatic
, nó kiểm tra thuộc tính$instance
đã được khởi tạo hay chưa? Nếu chưa khởi tạo thì khởi tạo, nếu khởi tạo rồi thì sẽ trả về kết quả của lần khởi tạo đó. Điều này giúp việc khởi tạo đối tượng sẽ chỉ xảy ra một lần duy nhất cho dù bạn gọi hàmgetInstance()
bao nhiêu lần đi nữa.
Với những cải tiến như trên, vấn đề tạo ra nhiều connection đã được giải quyết.
III. CÁC THÀNH PHẦN CÓ TRONG SINGLE DESIGN PATTERN
Tùy vào ngôn ngữ lập trình mà sẽ có cách triển khai singleton design pattern khác nhau, tuy nhiên chúng luôn có đủ các thành phần:
Client: Chính là nơi gọi hàm
Database::getInsance()
đó.Một class chứa phương thức để khởi tạo đối tượng, phương thức này đảm bảo Sẽ chỉ khởi tạo đối tượng một lần duy nhất ở lần gọi hàm đầu tiên, những lần sau sẽ chỉ trả về đối tượng đã được khởi tạo trước đó.
Dựa vào những thành phần trên, có thể tổng quát hóa Singleton design pattern trong PHP như sau:
IV. KHI NÀO THÌ SỬ DỤNG SINGLETON DESGIN PATTERN
Nói đơn giản thì Khi bạn muốn một class sẽ chỉ tạo ra một đối tượng xuyên suốt toàn bộ dự án thì sẽ sử dụng tới Singleton design pattern, giống như trường hợp kết nối tới database mà mình đề ở ở mục I. Tuy nhiên cái khó là làm sao để bạn biết rằng class đó chỉ nên tạo ra một đối tượng duy nhất. Để biết được điều này thì chỉ có cách là bạn phải thật sự hiểu mình đang làm gì và muốn làm gì, bằng cách đọc rõ yêu cầu hoặc phân tích rõ yêu cầu trước khi lao vào code.
Mình sẽ liệt kê cho bạn một số trường hợp nên sử dụng Single design pattern, tuy nó có thể không chính xác với bạn, nhưng cứ tham khảo xem thế nào nhé:
Khi muốn tạo một class quản lý việc kết nối tới database, hoặc các kết nối tương tự.
Khi tích hợp tính năng thanh toán qua các cổng thanh toán.
Khi bạn muốn quản lý các thông tin cấu hình của hệ thống thông qua các class
V. TỔNG KẾT
Tổng kết lại thì có một số ý quan trọng như sau:
Singleton là design pattern thuộc nhóm khởi tạo, class được triển khai theo singleton sẽ chỉ có thể tạo ra một đối tượng.
Để xác định khi nào sử dụng singleton, buộc bạn phải hiểu rõ mình sắp code cái gì, liệu nó có phải là đối tượng “global” toàn dự án hay không.
Singleton là một trong những design pattern được sử dụng phổ biến nhất.
Chào tạm biệt, hẹn gặp bạn bạn trong những bài viết tiếp theo.
Last updated