Mô tả chung
Java Singleton thuộc vào 1 trong 5 design
pattern của nhóm Creational Design Pattern.
Singleton là một mẫu thiết kế creational cho
phép bạn đảm bảo rằng một lớp chỉ có một đối tượng thể hiện và cung cấp truy cập
đối tượng này với phạm vi toàn ứng dụng.
Singleton đảm bảo chỉ duy nhất môt thể hiện mới
(new instance) được tạo ra và nó sẽ cung cấp cho bạn một phương thức để truy cập
đến thực thể đó.
Singleton giải quyết các vấn đề như:
- Làm thế nào có thể đảm bảo rằng một lớp chỉ
có một đối tượng
- Làm thế nào có thể truy cập dễ dàng một thể hiện
duy nhất của một lớp
- Làm thế nào để một lớp kiểm soát sự hiện thân của
nó
- Làm thế nào có thể hạn chế số lượng các thể hiện (instance) của một lớp
Cấu trúc
Một Singleton Pattern thường là 1 class (Class
Singleton) có các đặc điểm:
- Phương thức khởi tạo private để ngăn cản việc tạo
thể hiện của class từ các class khác
- Biến private static của class, nó là thể hiện
duy nhất của class.
- Có một phương thức là public static để trả về
thể hiện của class.
Một số cách thức sử dụng Singleton
1. Eager initialization
Singleton Class được khởi tạo ngay khi được gọi
đến. Đây là cách dễ nhất nhưng nó có một nhược điểm mặc dù instance đã được khởi
tạo mà có thể sẽ không dùng tới.
Ví dụ:
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
Cách làm tương tự như Eager initialization chỉ
khác phần static block cung cấp thêm option cho việc handle.
Ví dụ:
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
Là một cách làm mang tính mở rộng hơn so với 2
cách làm trên và hoạt động tốt trong từng thread đơn lẻ. Và tất nhiên vấn để xấu
sẽ sảy ra nếu chúng ta đang dùng nó với multi thread.
Ví dụ:
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
Thực chất với những gì ta đã nắm được từ Java
basic thì đã nghĩ ngay đến để method getInstance với synchronized .
5. Bill Pugh Singleton Implementation
Với cách làm này bạn sẽ tạo ra static nested class với vai trò 1 Helper khi muốn
tách biệt chức năng cho 1 class function rõ ràng hơn.
Ví dụ:
public class BillPughSingleton {
private BillPughSingleton(){}
private static class SingletonHelper{
private static final BillPughSingleton INSTANCE = new BillPughSingleton();
}
public static BillPughSingleton getInstance(){
return SingletonHelper.INSTANCE;
}
}
6. Using Reflection to destroy Singleton
Pattern
Reflection được dùng để huỷ tất cả các
singleton ở trên mà chúng ta đã tạo ra nó.
Ví dụ:
public class ReflectionSingletonTest {
public static void main(String[] args) {
EagerInitializedSingleton instanceOne = EagerInitializedSingleton.getInstance();
EagerInitializedSingleton instanceTwo = null;
try {
Constructor[] constructors = EagerInitializedSingleton.class.getDeclaredConstructors();
for (Constructor constructor : constructors) {
//Below code will destroy the singleton pattern constructor.setAccessible(true);
instanceTwo = (EagerInitializedSingleton) constructor.newInstance();
break;
}
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(instanceOne.hashCode());
System.out.println(instanceTwo.hashCode());
}
}
7. Enum Singleton
Khi dùng enum thì các params chỉ được khởi tạo
1 lần duy nhất, đây cũng là cách giúp bạn tạo ra Singleton instance. Tuy rằng
cách làm của nó có phần cứng nhắc .
Ví dụ:
public enum EnumSingleton {
INSTANCE;
public static void doSomething(){
//do something }
}
8. Serialization and Singleton
Serialization là một kỹ thuật sắp xếp đối tượng
cần lưu trữu một cách tuần tự. Dưới đây là quá trình đọc ghi dữ liệu khi tích hợp
singleton.
Ví dụ:
public class SerializableSingletonClass implements Serializable{
private static final long serialVersionUID = 1L;
private int value;
private String name;
private SerializableSingletonClass(int value, String name) {
if( value < 0 ) throw new IllegalArgumentException("Value may not be less than 0");
this.value = value;
this.name = Validate.notNull(name, "Name may not be null");
}
private static class SerializableSingletonHolder{
public static final SerializableSingletonClass INSTANCE;
static {
INSTANCE = new SerializableSingletonClass(0, "default");
}
}
private void readObject(ObjectInputStream stream) throws InvalidObjectException{
throw new InvalidObjectException("proxy required");
}
private Object writeReplace(){
return new SerializationProxy(this);
}
private static class SerializationProxy implements Serializable{
private static final long serialVersionUID = 1L;
public SerializationProxy(SerializableSingletonClass ignored) { } //Here is the question
private Object readResolve(){
return SerializableSingletonHolder.INSTANCE;
}
}
}
Đăng nhận xét