设计模式(一)单例模式:6-登记模式
思想:
登记模式,和前面5种单例不一样,从本质上来说,这是一种兼顾创建和管理单例的方法。
主要实现步骤是:
- 所有单例都继承于一个共同的父类。
- 子类通过父类完成单例的创建,父类使用反射创建子类。
- 父类持有一个 String-Object 的数据模型去存储创建出来的单例对象,一般称为 Registry。
- 第二次,及之后需要获取单例对象时,直接从 Registry 中获取。
public class RegisterSingleton { protected RegisterSingleton() { } protected static final Map<String, RegisterSingleton> registry = new HashMap<>(); private static final String name; private static volatile Object lock = new Object(); static { RegisterSingleton registerSingleton = new RegisterSingleton(); name = registerSingleton.getClass().getName(); registry.put(name, registerSingleton); } public static RegisterSingleton getInstance(String keyName) { if (keyName == null) { keyName = RegisterSingleton.name; } else if (registry.get(keyName) == null) { try { synchronized (lock) { Class<?> clazz = Class.forName(keyName); Constructor<?> constructor = clazz.getDeclaredConstructor(); constructor.setAccessible(true); RegisterSingleton singleton = (RegisterSingleton) constructor.newInstance(); registry.put(keyName, singleton); } } catch (Exception e) { throw new IllegalArgumentException(); } } return registry.get(keyName); } }
public final class RegisterSingletonChild extends RegisterSingleton { private static final String keyName = RegisterSingletonChild.class.getName(); private RegisterSingletonChild() { if (registry.get(keyName) != null) { throw new IllegalStateException(); } } public static RegisterSingletonChild getInstance() { return (RegisterSingletonChild) RegisterSingleton.getInstance(keyName); } public static void destroyInstance() { registry.remove(keyName); } }
- 反射?
这一点和 LazySingleton 的情况是一致的,反射是否能够打破单例取决于反射和 getInstance() 方法的调用顺序。
- 多线程?
在第一次创建对象时,进行了加锁的控制,保证了单例。
- 优势?劣势?
优势:达到了管理单例的效果,这个特点在很多框架中都有体现。例如,用 Spring IoC 创建的单例对象,都会放到一个 registry 里面。
劣势:对创建的单例有继承关系的要求;创建单例时使用了反射。