C# - C Sharp: Singleton Design Pattern


Khóa học qua video:
Lập trình Python All Lập trình C# All SQL Server All Lập trình C All Java PHP HTML5-CSS3-JavaScript
Đăng ký Hội viên
Tất cả các video dành cho hội viên

Singleton Design Pattern trong C# là một trong những mẫu thiết kế (Design Pattern) phổ biến nhất. Trong mẫu này, một lớp chỉ có một thể hiện trong chương trình cung cấp điểm truy cập global cho nó. Nói cách khác, một singleton là một lớp chỉ cho phép tạo một thể hiện duy nhất của chính nó và thường cấp quyền truy cập đơn giản vào thể hiện đó.

Có nhiều cách khác nhau để tạo một singleton pattern trong C#. Sau đây là các đặc điểm chung của một singleton pattern:

  • Hàm tạo đơn private và không tham số
  • Lớp sealed
  • Biến static để giữ một tham chiếu đến một thể hiện được tạo
  • Một cách public và static để lấy tham chiếu đến thể hiện đã tạo.

Ưu điểm của Singleton Design Pattern

  1. Singleton pattern có thể thực thi các interface.
  2. Có thể lazy-loaded và Khởi tạo tĩnh.
  3. Giúp ẩn các dependency.
  4. Cung cấp một điểm truy cập duy nhất cho một thể cụ thể, vì vậy rất dễ bảo trì.

Nhược điểm của Singleton Design Pattern

  1. Kiểm tra đơn vị hơi khó khăn vì nó đưa trạng thái global vào ứng dụng
  2. Giảm khả năng song song trong một chương trình bằng cách khóa (lock).

Lớp Singleton so với lớp tĩnh

Sau đây so sánh lớp Singleton với lớp tĩnh:
  1. Một lớp tĩnh không thể được mở rộng trong khi một lớp singleton có thể được mở rộng.
  2. Một lớp tĩnh không thể được khởi tạo trong khi một lớp singlenton lại có thể.
  3. Một lớp tĩnh được CLR tự động tải khi chương trình chứa lớp được tải.

Cách triển khai Singleton Pattern trong C#

Có một số cách để triển khai Singleton Pattern trong C#.
  1. Singleton không an toàn cho thread.
  2. Singleton an toàn có thread.
  3. Singleton an toàn có thread sử dụng Khóa kiểm tra kép.
  4. Thread an toàn không cần khóa.
  5. Sử dụng Lazy<T> của .NET 4.

Singleton không an toàn cho thread

  1. Đoạn mã sau không an toàn cho thread.
  2. Cả hai thread khác nhau đều có thể đã đánh giá thử nghiệm (nếu thể hiện == null) và nếu thấy nó true, thì cả hai đều tạo thể hiện, và điều này vi phạm singleton pattern.
     
    1. public sealed class Singleton1 {  
    2.     private Singleton1() {}  
    3.     private static Singleton1 instance = null;  
    4.     public static Singleton1 Instance {  
    5.         get {  
    6.             if (instance == null) {  
    7.                 instance = new Singleton1();  
    8.             }  
    9.             return instance;  
    10.         }  
    11.     }  
    12. }

Singleton an toàn với thread

  1. Đoạn mã sau an toàn cho thread.
  2. Trong đoạn mã, thread bị khóa trên một đối tượng được chia sẻ và kiểm tra xem một thể hiện đã được tạo hay chưa. Nó giải quyết vấn đề rào cản bộ nhớ và đảm bảo rằng chỉ một luồng sẽ tạo một thể hiện. Ví dụ: Vì mỗi lần chỉ có một luồng có thể ở trong phần code đó, nên khi luồng thứ hai vào đoạn code này, thì luồng thứ nhất sẽ tạo thể hiện, vì vậy biểu thức sẽ được đánh giá là false.
  3. Vấn đề lớn nhất với điều này là hiệu suất; hiệu suất bị ảnh hưởng vì khóa được yêu cầu mỗi khi một thể hiện được yêu cầu.
     
    1. public sealed class Singleton2 {  
    2.     Singleton2() {}  
    3.     private static readonly object instanceLock = new object();  
    4.     private static Singleton2 instance = null;  
    5.     public static Singleton2 Instance {  
    6.         get {
    7.             lock(instanceLock) {  
    8.                 if (instance == null) {  
    9.                     instance = new Singleton2();  
    10.                 }  
    11.                 return instance;  
    12.             }  
    13.         }  
    14.     }  
    15. }

Singleton an toàn cho thread sử dụng khóa kép

Trong đoạn mã sau, thread bị khóa trên một đối tượng được chia sẻ và kiểm tra xem một thể hiện đã được tạo hay chưa bằng cách kiểm tra kép.
  1. public sealed class Singleton3 {  
  2.     Singleton3() {}  
  3.     private static readonly object lock = new object();  
  4.     private static Singleton3 instance = null;  
  5.     public static Singleton3 Instance {  
  6.         get {  
  7.             if (instance == null) {  
  8.                 lock(lock) {  
  9.                     if (instance == null) {  
  10.                         instance = new Singleton3();  
  11.                     }  
  12.                 }  
  13.             }  
  14.             return instance;  
  15.         }  
  16.     }  
  17. }

Singleton an toàn cho thread mà không cần sử dụng khóa và không khởi tạo Lazy

  1. Việc triển khai ở trên trông giống như một đoạn mã rất đơn giản.
  2. Kiểu triển khai này có một hàm tạo tĩnh, do đó, nó chỉ thực thi một lần cho mỗi Miền ứng dụng.
  3. Nó không Lazy như cách thực hiện khác.
    1. public sealed class Singleton4    
    2. {    
    3.     private static readonly Singleton4 instance = new Singleton4();    
    4.     static Singleton4()    
    5.     {    
    6.     }    
    7.     private Singleton4()    
    8.     {    
    9.     }    
    10.     public static Singleton4 Instance    
    11.     {    
    12.         get    
    13.         {    
    14.             return instance;    
    15.         }    
    16.     }    
    17. }

Sử dụng Lazy<T> của .NET 4 trở lên

  1. Nếu bạn đang sử dụng .NET 4 trở lên thì bạn có thể sử dụng loại System.Lazy<T> để làm cho lazy trở nên thực sự đơn giản.
  2. Bạn có thể truyền một delegate cho hàm tạo để gọi hàm tạo Singleton, việc này được thực hiện dễ dàng nhất với biểu thức lambda.
  3. Cho phép bạn kiểm tra xem phiên bản đã được tạo hay chưa bằng thuộc tính IsValueCreated.
    1. public sealed class Singleton5    
    2. {    
    3.     private Singleton5()    
    4.     {    
    5.     }    
    6.     private static readonly Lazy<Singleton5> lazy = new Lazy<Singleton5>(() => new Singleton5());    
    7.     public static Singleton5 Instance    
    8.     {    
    9.         get    
    10.         {    
    11.             return lazy.Value;    
    12.         }    
    13.     }    
    14. }
» Tiếp: Con trỏ (Pointer) trong C#
« Trước: Namespace
Khóa học qua video:
Lập trình Python All Lập trình C# All SQL Server All Lập trình C All Java PHP HTML5-CSS3-JavaScript
Đăng ký Hội viên
Tất cả các video dành cho hội viên
Copied !!!