Extending singleton (singleton inheritance)


In this example, base class Singleton provides getMessage() method that returns "Hello world!" message.

The program demonstrates creating a base singleton class with two extended types. The user can choose between the types by setting the type variable. The extended types use reflection to create instances, as the constructors are private inner classes.

import java.lang.reflect.*;
 
enum SingletonType {
    UNKNOWN,
    FIRST_TYPE,
    SECOND_TYPE
}
 
class SingletonBase {
    private class FirstTypeSingleton extends SingletonBase {
        private FirstTypeSingleton() {
            super();
        }
 
        @Override
        public String getMessage() {
            return super.getMessage().toUpperCase();
        }
    }
 
    private class SecondTypeSingleton extends SingletonBase {
        private SecondTypeSingleton() {
            super();
        }
 
        @Override
        public String getMessage() {
            return super.getMessage().toLowerCase();
        }
    }
 
    private static SingletonType type = SingletonType.UNKNOWN;
    private static SingletonBase instance;
 
    public static void setType(SingletonType type) {
        SingletonBase.type = type;
    }
 
    public static SingletonBase getInstance() throws NoSuchMethodException, IllegalAccessException, 
	InvocationTargetException, InstantiationException {
        if (instance == null) {
            synchronized (SingletonBase.class) {
                if (instance == null) {
                    SingletonBase singleton = new SingletonBase();
                    switch (type) {
                        case UNKNOWN:
                            instance = singleton;
                            break;
                        case FIRST_TYPE:
                            Constructor<FirstTypeSingleton> firstTypeConstructor = FirstTypeSingleton.class.
										getDeclaredConstructor(SingletonBase.class);
                            firstTypeConstructor.setAccessible(true);
                            instance = firstTypeConstructor.newInstance(singleton);
                            break;
                        case SECOND_TYPE:
                            Constructor<SecondTypeSingleton> secondTypeConstructor = SecondTypeSingleton.
										class.getDeclaredConstructor(SingletonBase.class);
                            secondTypeConstructor.setAccessible(true);
                            instance = secondTypeConstructor.newInstance(singleton);
                            break;
                    }
                }
            }
        }
        return instance;
    }
 
    protected String message;
 
    private SingletonBase() {
        message = "Hello world!";
    }
 
    public String getMessage() {
        return message;
    }
}
 
public class CustomSingletonExample {
    public static void main(String args[]) {
        SingletonBase singleton = null;
        try {
            singleton = SingletonBase.getInstance();
        } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException | InstantiationException e) {
            e.printStackTrace();
        }
        System.out.println(singleton.getMessage());
    }
}

Basic Programs