`

登记式单例实现单例模式的继承(限定一个抽象类的所有子类都必须是单例)

阅读更多

 

       根据单例实例构造的时机和方式不同,单例模式还可以分成几种,但对于这种通过私有化构造函数,静态方法提供实例的单例类而言,是不支持继承的。这种模式的单例实现要求每个具体的单例类自身来维护单例实例和限制多个实例的生成。可以采用另外一种实现单例的思路:登记式单例,来使得单例对继承开放。

 

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;

public abstract class AbstractSingleton {
    private static Map<String, AbstractSingleton> registryMap = new HashMap<String, AbstractSingleton>();
    
    AbstractSingleton() throws SingletonException{
        String clazzName = this.getClass().getName();
        if (registryMap.containsKey(clazzName)){
            throw new SingletonException("Cannot construct instance for class " + clazzName + ", since an instance already exists!");
        } else {
            synchronized(registryMap){
                if (registryMap.containsKey(clazzName)){
                    throw new SingletonException("Cannot construct instance for class " + clazzName + ", since an instance already exists!");
                } else {
                    registryMap.put(clazzName, this);
                }
            }
        }
    }
    
    @SuppressWarnings("unchecked")
    public static <T extends AbstractSingleton> T getInstance(final Class<T> clazz) throws InstantiationException, IllegalAccessException{
        String clazzName = clazz.getName();
        if(!registryMap.containsKey(clazzName)){
            synchronized(registryMap){
                if(!registryMap.containsKey(clazzName)){
                    T instance = clazz.newInstance();
                    return instance;
                }
            }
        }
        return (T) registryMap.get(clazzName);
    }
    
    public static AbstractSingleton getInstance(final String clazzName) 
            throws ClassNotFoundException, InstantiationException, IllegalAccessException{
        if(!registryMap.containsKey(clazzName)){
            Class<? extends AbstractSingleton> clazz = Class.forName(clazzName).asSubclass(AbstractSingleton.class);
            synchronized(registryMap){
                if(!registryMap.containsKey(clazzName)){
                    AbstractSingleton instance = clazz.newInstance();
                    return instance;
                }
            }
        }
        return registryMap.get(clazzName);
    }
    
    @SuppressWarnings("unchecked")
    public static <T extends AbstractSingleton> T getInstance(final Class<T> clazz, Class<?>[] parameterTypes, Object[] initargs) 
            throws SecurityException, NoSuchMethodException, IllegalArgumentException, 
            InvocationTargetException, InstantiationException, IllegalAccessException{
        String clazzName = clazz.getName();
        if(!registryMap.containsKey(clazzName)){
            synchronized(registryMap){
                if(!registryMap.containsKey(clazzName)){
                    Constructor<T> constructor = clazz.getConstructor(parameterTypes);
                    T instance = constructor.newInstance(initargs);
                    return instance;
                }
            }
        }
        return (T) registryMap.get(clazzName);
    }
    
    static class SingletonException extends Exception {
        /**
         * 
         */
        private static final long serialVersionUID = -8633183690442262445L;

        private SingletonException(String message){
            super(message);
        }
    }

}

      以上代码实现了一个抽象类,该类使用一个静态的Map来维护各个子类的实例。在构造方法中判断对应子类的实例是否已登记,若已登记则抛出一个SingletonException阻止实例的创建。由于构造子类的实例必须先执行父类的构造方法,因此子类第一次通过构造方法创建对象时,父类构造方法会自动把实例登记,以后再调用该子类的构造方法则会抛出异常,即便子类构造方法是public的,也只能成功创建一个实例。同时父类提供几个getInstance方法,通过传入需要获取实例的子类Class对象或Class限定名来获取对应的实例。前两个方法需要子类提供无参构造方法,第三个getInstance方法提供子类只有有参构造方法的情况下,通过参数构造子类对象。下面给出两个具体实现类的例子:

public class ConcreteSingleton1 extends AbstractSingleton {

    public ConcreteSingleton1() throws SingletonException {
        super();
        // TODO Auto-generated constructor stub
    }
    
    public static ConcreteSingleton1 getInstance(){
        try {
            return AbstractSingleton.getInstance(ConcreteSingleton1.class);
        } catch (InstantiationException e) {
            // TODO Auto-generated catch block
            // will not happen
            e.printStackTrace();
            return null;
        } catch (IllegalAccessException e) {
            // TODO Auto-generated catch block
            // will not happen
            e.printStackTrace();
            return null;
        }
    }

}

public class ConcreteSingleton2 extends AbstractSingleton {
    private final int value;

    public ConcreteSingleton2(int value) throws SingletonException {
        super();
        // TODO Auto-generated constructor stub
        this.value = value;
    }
    
    public static ConcreteSingleton2 getInstance(int value){
        try {
            return AbstractSingleton.getInstance(ConcreteSingleton2.class, new Class<?>[]{int.class}, new Object[]{value});
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            return null;
        } 
    }
    
    public int getValue(){
        return value;
    }

}

 原文出处:

http://www.cnblogs.com/wang9192/p/3975748.html

分享到:
评论

相关推荐

    设计模式的代码样例

    单例模式是将将构造方法限定为private避免了类在外部被实例化,在同一个虚拟机范围内,Singleton的唯一实例只能通过提供的入口获得[例如getInstance()方法], 事实上,通过Java反射机制是能够实例化构造方法为private...

    鸟笼逻辑仅仅用于自己观看 文件已加密

    1.一个抽象类至少有一个抽象方法,每个抽象方法必须在返回类型之前使用abstract限定符。不能实例化一个抽象类对象。...一个类必须至少实现接口中的一个方法,如果一个类没有实现接口中的所有的方法则他是抽象类。

    java类速查,含有所有类的子类及方法

    需要的人就下,不过要资源分,应为最近需要积分dddddd

    使用Java实现一个基于内存的英文全文检索搜索引擎【100012394】

    学生必须继承这些预定义的抽象类和和实现预定义接口来完成实验的功能,不能修改抽象类和接口里规定好的数据成员、抽象方法;也不能在预定义抽象类和接口里添加自己新的数据成员和方法。但是实现自己的子类和接口实现...

    Java 语言基础 —— 非常符合中国人习惯的Java基础教程手册

     abstract 说明一个类为抽象类,抽象类是指不能直接实例化对象的类。  final 说明一个类为最终类,即改类不能再有子类。  public 说明类为公共类,该类可以被当前包以外的类和对象使用。  private 说明类为...

    JAVA复习资料

    19、如果一个Java Applet源程序文件只定义有一个类,该类的类名为MyApplet,则类MyApplet必须是 Applet 类的子类并且存储该源程序文件的文件名必须为 MyApplet.java 。 20、 一个Java Application源程序文件名为...

    c.c++找工作面试重点结构图-mindmanager

    延续化 先定义一个抽象基类,该基类中有些操作并未实现。然后定义非抽象的派生类,实现抽象基类中定义的操作。例如,虚函数就属此类情况。这时,派生类是抽象的基类的实现,即可看成是基类定义的延续。这也是派生类...

    Python面向对象之接口、抽象类与多态详解

    二:声明某个子类兼容于某基类,定义一个接口类Interface,接口类中定义了一些接口名(就是函数名)且并未实现接口的功能,子类继承接口类,并且实现接口中的功能 接口主要是java等语言中的概念,python中并没有明确...

    利用反射,根据类得完全限定名获得该类得实例

    利用反射技术,根据类的完全限定名获得该类的实例对象。包括无参数或带参数的实例化。感兴趣的可以看看!

    Java 限制子类访问的方法分析

    主要介绍了Java 限制子类访问的方法,结合实例形式分析了java类的继承与访问相关操作技巧与使用注意事项,需要的朋友可以参考下

    UML和模式应用(架构师必备).part02.rar

    8.3 过程:计划下一个迭代 第9章 领域模型 9.1 示例 9.2 什么是领域模型 9.3 动机:为什么要创建领域模型 9.4 准则:如何创建领域模型 9.5 准则:如何找到概念类 9.6 示例:寻找和描绘概念类 9.7 准则:敏捷...

    UML和模式应用(架构师必备).part06.rar

    8.3 过程:计划下一个迭代 第9章 领域模型 9.1 示例 9.2 什么是领域模型 9.3 动机:为什么要创建领域模型 9.4 准则:如何创建领域模型 9.5 准则:如何找到概念类 9.6 示例:寻找和描绘概念类 9.7 准则:敏捷...

    虚拟数据层 Struts2、Hibernate、Spring整合的泛型DAO Version 2010.9.27

    1)dao类的繁多,很多设计都是一个entity对应一个dao (不同的只有类名和方法名) 2)dao接口需要维护的method庞大。 3)业务逻辑改变时,dao需要同时修改两个类文件(接口和实现类) 在本文中,我将为您展示如何...

    泛型dao 泛型dao 泛型dao

    1)dao类的繁多,很多设计都是一个entity对应一个dao (不同的只有类名和方法名) 2)dao接口需要维护的method庞大。 3)业务逻辑改变时,dao需要同时修改两个类文件(接口和实现类) 在本文中,我将为您展示如何...

    dzlzh#shiyanlou-courses#2.模式限定修饰与重叠模式定义1

    一、实验简介 二、模式限定修饰 三、重叠模式定义 四、实验总结

    疯狂JAVA讲义

    学生提问:既然内部类是外部类的成员,是否可以为外部类定义子类,在子类中再定义一个内部类来重写其父类中的内部类? 211 6.7.4 局部内部类 211 6.7.5 匿名内部类 212 6.7.6 闭包(Closure)和回调 215 6.8 ...

    限定鼠标区域LimitCursorPos限定鼠标区域LimitCursorPos

    限定鼠标区域LimitCursorPos限定鼠标区域LimitCursorPos限定鼠标区域LimitCursorPos

    【04-面向对象(上)】

    •Java里的继承都是单继承,也就是只能有一个直接的父类,可以有n个间接父类。 重写父类的方法 •方法的重写要遵循“两同两小一大” 指的是:方法名相同,形参列表相同。返回值类型更小或相同,抛出的...

    UML和模式应用(架构师必备).part01.rar

    8.3 过程:计划下一个迭代 第9章 领域模型 9.1 示例 9.2 什么是领域模型 9.3 动机:为什么要创建领域模型 9.4 准则:如何创建领域模型 9.5 准则:如何找到概念类 9.6 示例:寻找和描绘概念类 9.7 准则:敏捷...

    UML和模式应用(架构师必备).part07.rar

    8.3 过程:计划下一个迭代 第9章 领域模型 9.1 示例 9.2 什么是领域模型 9.3 动机:为什么要创建领域模型 9.4 准则:如何创建领域模型 9.5 准则:如何找到概念类 9.6 示例:寻找和描绘概念类 9.7 准则:敏捷...

Global site tag (gtag.js) - Google Analytics