Singleton pattern

Singleton Pattern

Lời dẫn: Singleton pattern giới hạn việc khởi tạo của một lớp và đảm bảo chỉ có duy nhất một đối tượng của lớp tồn tại trong máy ảo java. Có vẻ đây là pattern đơn giản nhất nhưng trong thực tế nó lại là một trong những pattern được ứng dụng nhiều nhất. Thực tế thì việc triển khai Singleton pattern là một chủ đề nhiều tranh cãi giữa các nhà phát triển.

Để triển khai Singleton Pattern, chúng ta có nhiều cách tiếp cận khác nhau nhưng tất cả chúng đều có chung những khái niệm sau:
  • Khởi tạo ở chế độ private nhằm giới hạn việc khởi tạo lớp từ các lớp khác.
  • Biến tĩnh ở chế độ private của cùng lớp đại diện cho đối tượng duy nhất của lớp.
  • Phương thức tĩnh ở chế độ public để trả về đối tượng của lớp.
Các tiểu mục tiếp theo của bài viết này sẽ trình bày các cách triển khai khác nhau của Singleton Pattern.

1. Eager initialization
Với phương pháp này, đối tượng của lớp Singleton được tạo ra vào thời điểm lớp được tải lên (vào bộ nhớ - lời người dịch). Đây là phương thức dễ nhất để tạo một lớp singleton. Tuy nhiên yếu điểm của nó là đối tượng vẫn được tạo ra dù cho ứng dụng không sử dụng đến nó. Đoạn mã sau minh họa phương pháp này.


package com.journaldev.singleton;

public class EagerInitializedSingleton {
    
    private static final EagerInitializedSingleton instance = new EagerInitializedSingleton();
    
    //private constructor to avoid client applications to use constructor
    private EagerInitializedSingleton(){}

    public static EagerInitializedSingleton getInstance(){
        return instance;
    }
}
2. Static block initialization
Phương pháp này tương tự với Eager initialization, ngoại trừ việc đối tượng của lớp này được khởi tạo trong khối static đi kèm với bẫy ngoại lệ. 


package com.journaldev.singleton;

public class StaticBlockSingleton {

    private static StaticBlockSingleton instance;
    
    private StaticBlockSingleton(){}
    
    //static block initialization for exception handling
    static{
        try{
            instance = new StaticBlockSingleton();
        }catch(Exception e){
            throw new RuntimeException("Exception occured in creating singleton instance");
        }
    }
    
    public static StaticBlockSingleton getInstance(){
        return instance;
    }
}
3. Lazy initialization
Phương pháp này khởi tạo đối tượng của lớp ngay bên trong phương thức truy cập chế độ public của lớp.
package com.journaldev.singleton;

public class LazyInitializedSingleton {

    private static LazyInitializedSingleton instance;
    
    private LazyInitializedSingleton(){}
    
    public static LazyInitializedSingleton getInstance(){
        if(instance == null){
            instance = new LazyInitializedSingleton();
        }
        return instance;
    }
}

4. Thread safe singleton
Để hoạt động tốt đối với các ứng dụng đa tiến trình (multi-thread) chế độ synchronized cần được thêm vào phương thức truy cập như sau:
package com.journaldev.singleton;

public class ThreadSafeSingleton {

    private static ThreadSafeSingleton instance;
    
    private ThreadSafeSingleton(){}
    
    public static synchronized ThreadSafeSingleton getInstance(){
        if(instance == null){
            instance = new ThreadSafeSingleton();
        }
        return instance;
    }
    
}
Một cách khác để xây dựng phương thức truy cập tới đối tượng của lớp Singlton trong chương trình multi-thread như sau:
public static ThreadSafeSingleton getInstanceUsingDoubleLocking(){
    if(instance == null){
        synchronized (ThreadSafeSingleton.class) {
            if(instance == null){
                instance = new ThreadSafeSingleton();
            }
        }
    }
    return instance;
}

5. Serialization and Singleton
Đoi khi trong các hệ thống phân tán, chúng ta cần triển khai giao diện Serialize với các lớp dạng Singleton nhằm phục vụ mục đích lưu trữ trạng thái vào tập tin hệ thống. Một ví dụ điển hình như sau:
package com.journaldev.singleton;

import java.io.Serializable;

public class SerializedSingleton implements Serializable{

    private static final long serialVersionUID = -7604766932017737115L;

    private SerializedSingleton(){}
    
    private static class SingletonHelper{
        private static final SerializedSingleton instance = new SerializedSingleton();
    }
    
    public static SerializedSingleton getInstance(){
        return SingletonHelper.instance;
    }
    
}


1 comment :