Hotline
0388011834
Trang chủ/ Góc lập trình/Design Patterns

Creational Patterns - Singleton



Khái niệm

Singleton là một mẫu thiết kế thuộc nhóm khởi tạo (Creational Pattern) cho phép bạn đảm bảo rằng một lớp (class) chỉ có một thể hiện (instance) duy nhất trong suốt vòng đời ứng dụng. Nó cung cấp một điểm truy cập toàn cục (global access point) đến instance này.

    1.  

Các thành phần chính

  • Singleton: Đây là một lớp khai báo một phương thức tĩnh (thường là getInstance) mà trả về thể hiện (instance) của chính lớp đó.
    1.  

Ưu điểm

  • Kiểm soát chặt chẽ việc khởi tạo, tiết kiệm bộ nhớ.
    1.  

Nhược điểm

  • Có thể gây khó khăn trong việc Unit Test và gây ra các vấn đề về đa luồng (thread-safety) nếu không triển khai đúng cách.
    1.  

Ví dụ thực tế

  • Bài toán

Ta có một đối tượng mà cần gọi đến nhiều lần trong vòng đời của một ứng dụng (ví dụ: Đối tượng database cho việc thao tác cơ sở dữ liệu). Ta không muốn mỗi lần gọi tới lại phải tạo mới thể hiện của đối tượng đó để sử dụng. Vì việc làm này sẽ lặp đi lặp lại và có thể gây tốn bộ nhớ.

  • Phân tích bài toán

Đối tượng đó sẽ là một biến toàn cục, sẽ được sử dụng trong vòng đời của ứng dụng.

Nếu ta khởi tạo thể hiện mới cho nó mỗi khi sử dụng, việc này sẽ làm mất đi tính duy nhất của nó. Và ta cũng không chắc mỗi lần khởi tạo đó có làm ảnh hưởng tới các thuộc tính bên trong đối tượng hay không.

Cách triển khai

Mẫu thiết kế này chỉ bao gồm một thành phần duy nhất là lớp Singleton, vì vậy ta sẽ thiết kế lớp đó về cơ bản như sau:

    public sealed class Singleton
    {
        private Singleton() { }

 
        private static Singleton _instance;

 
        public string Attr1 { get; set; }

 
        public static Singleton GetSingleton()
        {
            if (_instance == null)
            {
                _instance = new Singleton
                {
                    Attr1 = Guid.NewGuid().ToString()
                };
            }

 
            return _instance;
        }
    }

Để giảm thiểu rủi ro từ việc kế thừa hoặc tạo thể hiện mới, ta sẽ thêm thuộc tính sealed cho lớp, và private cho hàm khởi tạo của lớp.

Và ta sẽ cung cấp một phương thức GetSingleton để trả về thể hiện của lớp. Phương thức này sẽ có thuộc tính public để cho các lớp khác có thể gọi tới để lấy thể hiện của lớp.

Cuối cùng, ta sẽ có hàm Main mô phỏng như sau:

    class ClientSingleton
    {
        public void Main()
        {
            Singleton s1 = Singleton.GetSingleton();
            Console.WriteLine("Tao the hien lan 1: Gia tri cua thuoc tinh Attr1 = {0:s}", s1.Attr1);

 
            Singleton s2 = Singleton.GetSingleton();
            Console.WriteLine("Tao the hien lan 2: Gia tri cua thuoc tinh Attr1 = {0:s}", s2.Attr1);

 
            if (s1 == s2)
            {
                Console.WriteLine("Ca 2 bien deu chua dung the hien giong nhau.");
            }
            else
            {
                Console.WriteLine("2 bien chua dung nhung the hien khac nhau.");
            }
        }
    }

Kết quả chạy chương trình sẽ như sau:

Như vậy, ta thấy rằng qua 2 lần tạo thể hiện của đối tượng, thuộc tính Attr1 đều giống nhau ở cả 2 lần tạo. Điều đó cho thấy rằng, chỉ duy nhất một thể hiện được tạo ra trong vòng đời ứng dụng.

    1.  

Kết luận

Như vậy, qua bài viết này, tôi hi vọng các bạn sẽ nắm được khái niệm cũng như biết được việc khi nào thì nên áp dụng mẫu thiết kế Singleton vào trong ứng dụng của mình.

Ví dụ tôi đưa đôi khi không chính xác và thuyết phục hoàn toàn, rất mong sự góp ý từ phía các bạn để tôi có thể củng cố thêm kiến thức cho bản thân mình.