`

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

阅读更多

 

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

 

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

分享到:
评论

相关推荐

    单例模式讲解说明与实例

    单例模式是 Java 中一种常见的设计模式,分为懒汉式单例、饿汉式单例和登记式单例三种。单例模式有以下特点: 1. 单例类只能有一个实例。 2. 单例类必须自己创建自己的唯一实例。 3. 单例类必须给所有其他对象提供...

    Java 23种设计模式09单例模式

    1. **身份证号码**:在该实例中,身份证号码被视为一个单例,确保每个公民的身份证号码在全球范围内都是唯一的。当首次申请身份证时,系统会为其分配一个身份证号码,后续即使因故需要补办,仍然使用原有的号码,...

    day08_继承、抽象类、包.pdf

    在Java中,继承允许我们创建一个新类(子类),这个新类能够获取另一个已存在的类(父类)的属性和方法,从而实现代码的复用和扩展。这有助于形成类的层次结构,更好地模拟现实世界中的各种关系。 首先,我们来看...

    第4章 接口、抽象类与包.ppt

    例如,可以有一个抽象的`Vehicle`类,它的子类如`Car`和`Bike`分别实现具体的细节。 包是Java中的命名空间,用于组织类和接口。通过将相关类和接口放入同一个包,可以避免名称冲突并提供更好的模块化。创建包使用`...

    设计模式的代码样例

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

    反射取继承子类.rar

    这个压缩包“反射取继承子类.rar”很可能包含了一个示例或教程,专注于如何利用反射机制来获取一个类的所有继承子类。这个主题在开发复杂和动态系统时特别有用,因为它提供了对类层次结构的深入洞察。 首先,我们...

    java 面向对象变成

    - **继承(Inheritance)**:继承允许一个类(子类)继承另一个类(父类)的特性,从而实现代码重用和扩展。 - **多态(Polymorphism)**:多态允许一个接口有多种不同的实现,或者一个对象可以有多种形态。Java...

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

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

    j2se 包、接口和抽象类

    Java不支持多继承,但一个类可以实现多个接口。接口用于定义行为规范,让不同类实现相同的行为。接口可以扩展其他接口,使用`extends`关键字,例如`interface MyInterface extends ParentInterface`。 在Java中,...

    面向对象(高级)知识点强势总结!!!

    + 内部类是指在一个类中的另一个类 + 内部类可以访问外部类的成员变量和方法 + 内部类可以在外部类中使用 九、枚举类:enum * 枚举类的使用 + 枚举类是指一个特殊的类 + 枚举类的实例可以被限定 + 枚举类...

    java反射获取所有属性,获取所有get方法,包括子类父类

    Java反射是Java编程语言中的一个强大工具,它允许运行中的Java程序对自身进行检查并且可以直接操作程序的内部属性。在Java中,反射主要用于在运行时分析类和对象,包括访问私有成员、调用私有方法、创建动态代理等。...

    java实验报告5java实验报告5.doc

    3. **抽象类和抽象方法**:虽然实验中没有明确提到抽象类,但在Java中,如果一个类包含至少一个抽象方法,那么这个类必须声明为抽象类。抽象方法没有具体的实现,需要由其子类来完成。子类继承抽象类后,必须实现...

    16-1【SV精通3】类的方法和继承_动态对象_包的使用.zip

    继承是OOP中的一个重要特性,允许一个类(子类或派生类)继承另一个类(父类或基类)的属性和方法。这有助于代码重用,并且可以构建层次结构,使得更具体的类可以扩展或修改通用类的行为。在Java中,我们使用关键字`...

    基对象引用子类实例(C# 形象说明:父母可以代表孩子做很多事情)

    3. **接口实现**:如果子类实现了某个接口,而该接口被基类引用,那么子类实例也可以被视为接口类型的对象。 4. **抽象类和虚方法**:通过在基类中定义抽象方法或虚方法(`virtual`),子类可以重写这些方法以提供...

    工厂模式代码

    1. **Java反射机制**:在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为Java语言的...

    C++单项选择复习题

    6. 虚函数必须是非静态成员函数,可以被覆盖并由派生类继承。 7. 抽象类至少包含一个纯虚函数,不能直接实例化,通常作为接口使用。 8. 文件操作在C++中通常涉及`fstream.h`头文件,如`ifstream`和`ofstream`类...

    java面向对象

    在Java中,继承使用`extends`关键字来实现,它允许一个类继承另一个类的属性和方法。通过继承,子类可以重用父类的代码,提供代码复用性和模块化的特性。Java支持单继承,即一个类只能继承一个父类。 以上就是从...

    java程序设计思考与练习

    不能直接创建抽象类的对象,必须通过继承并实现所有抽象方法才能创建子类的对象。例如,`abstract class MyBase {}`定义了一个抽象类。 ### 12. 关键字`abstract`的用途 `abstract`关键字可以用来修饰类、方法,但...

    第十一章继承与多态

    `threeD` 类继承了 `twoD` 类的所有公有成员和受保护成员,并且增加了新的成员变量 `z` 和相关的成员函数。 #### 4. 多态 多态是指允许将子类对象赋值给父类引用或指针的能力,以及基于指向基类的指针或引用调用虚...

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

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

Global site tag (gtag.js) - Google Analytics