设计模式(一)单例模式: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 里面。

  劣势:对创建的单例有继承关系的要求;创建单例时使用了反射。

 

posted @ 2017-09-10 18:12  Gerrard_Feng  阅读(638)  评论(0编辑  收藏  举报