[C#] Giới thiệu Singleton trong Design Pattern - Duy nhất một thể hiện
Bài viết hôm nay, mình xin giới thiệu với các bạn về Singleton trong Design Pattern C#. Singleton là một design pattern được sử dụng cũng phổ biến. Nó đưa ra cách thiết kế để đảm bảo rằng chỉ tạo ra không quá một thể hiện của một lớp và thể hiện ...
Bài viết hôm nay, mình xin giới thiệu với các bạn về Singleton trong Design Pattern C#.
Singleton là một design pattern được sử dụng cũng phổ biến. Nó đưa ra cách thiết kế để đảm bảo rằng chỉ tạo ra không quá một thể hiện của một lớp và thể hiện này có thể được truy cập từ bất cứ đâu.
CÁC THÀNH PHẦN THAM GIA
Trong Singleton chỉ cần xây dựng trên duy nhất một lớp, trên lớp này chia thành 2 nhóm thành phần:
Nhóm đảm bảo chỉ tạo được một thể hiện: hàm khởi tạo là private hoặc protected để không tạo được thể hiện từ bên ngoài. Biến instance là private và static để đảm bảo chỉ có 1 thể hiện. Thuộc tính Instance cung cấp giao diện để truy xuất đến thể hiện duy nhất.
Nhóm nghiệp vụ: chứa các thuộc tính và phương thức nghiệp vụ đặc thù của lớp.
CÀI ĐẶT SINGLETON TRONG C#
Để đơn giản, tôi sẽ không cài đặt nhóm nghiệp vụ cho class Singleton:
class MainApp { static void Main() { Singleton s1 = Singleton.Instance; Singleton s2 = Singleton.Instance; // Kiểm tra xem có đúng 2 biến trỏ đến cùng 1 thể hiện không if (s1 == s2) Console.WriteLine("SAME"); Console.ReadKey(); } } /// <summary> /// The 'Singleton' class /// </summary> class Singleton { private static Singleton _instance; protected Singleton() { } public static Singleton Instance() { // nếu chưa có thì tạo thể hiện duy nhất if (_instance == null) _instance = new Singleton(); return _instance; } }
Kết quả:
SAME
Nhận xét:
Singleton sử dụng tính đóng gói, bao bọc (encapsulate) của lập trình hướng đối tượng để che dấu, bảo vệ biến _instance (chỉ khởi tạo và gán duy nhất 1 lần) đồng thời che dấu phương thức khởi tạo với bên ngoài.
MỘT VÍ DỤ TRONG THỰC TẾ
Tôi sẽ lấy ví dụ cho trường hợp cân bằng tải (LoadBalancing) cho server. Bạn có một server chuyên nhận yêu cầu để xử lý và trả về kết quả. Server của bạn chỉ được khoảng 1000 request / giây, nếu trên số đó server của bạn sẽ bị quá tải. Trong thực tế số lượng request lên tới hơn 3000 / giây. Bạn đã đã đầu tư thêm 3 con server mới nữa để đáp ứng và bạn cần có 1 server đúng ra cân bằng tải cho 4 server đúng sau. Trong trường hợp này, server cân bằng tải có thể thiết kế theo Singleton, mọi request đều tham chiếu tới cùng một server cân bằng tải và server này chỉ có 1.
Tôi thực hiện cài đặt giống như mẫu bên trên:
class MainApp { static void Main() { // Giả lập 15 request for (var i = 0; i < 15; i++) { var balancer = LoadBalancer.GetLoadBalancer(); Console.WriteLine("Chuyen den: " + balancer.Server); } Console.ReadKey(); } } /// <summary> /// The 'Singleton' class /// </summary> class LoadBalancer { private static LoadBalancer _instance; private readonly List<string> _servers = new List<string>(); private readonly Random _random = new Random(); protected LoadBalancer() { // Tạo ra 4 server for (var i = 0; i < 4; i++) _servers.Add("Server " + (i + 1)); } public static LoadBalancer GetLoadBalancer() { if (_instance == null) _instance = new LoadBalancer(); return _instance; } // Trả về ngẫu nhiên 1 server // Đơn giản nhưng cân bằng tải cũng khá hiệu quả public string Server { get { int r = _random.Next(_servers.Count); return _servers[r]; } } }
Kết quả nhận được sẽ tương tự như sau:
Chuyen den: Server 1
Chuyen den: Server 1
Chuyen den: Server 2
Chuyen den: Server 4
Chuyen den: Server 1
Chuyen den: Server 2
Chuyen den: Server 4
Chuyen den: Server 2
Chuyen den: Server 4
Chuyen den: Server 1
Chuyen den: Server 3
Chuyen den: Server 1
Chuyen den: Server 4
Chuyen den: Server 3
Chuyen den: Server 4
Ở đây, nếu ta để ý thật kỹ đoạn code cài đặt cho phương thức GetLoadBalancer() thì các bạn sẽ thấy có vấn đề khi hàm này được chạy đa luồng. Với ví dụ trên, 15 request được giả lập nhưng lại là chạy tuần tự, nếu 15 request chạy đa luồng và song song nhau, chúng gọi GetLoadBalancer() gần như cùng thời điểm và _instance có thể đều chưa được khởi tạo giá trị và đều qua được chốt chặn if (_instance == null). Nếu như vậy có thể sẽ tạo ra 15 thể hiện khác nhau.
laptrinhvb.net via http://tek.eten.vn