KarlKnechtel: This is a way of getting a set of related Singleton objects in JavaLanguage. The constructors are actually not made private, but instead get protection from the Java packaging mechanism, allowing a Factory class to do LazyInstantiation?. The downside is that if you want to ensure that the constructors can't be called from outside, then you have to either be able to tell the Factory which class you want, or be able to let it decide.
Say all your Singleton objects have some superclass (reasonable if they represent, say, options for State or Strategy) or implement a common interface. Then, create a package with the following contents:
Example code:
// Bars.java - factory package barpkg; // important! public class Bars { public static Hashtable instances; // This particular implementation is not doing a LazyInstantiation?... static { instances.put("foo", new FooBar()); instances.put("fee", new FeeBar()); instances.put("foe", new FoeBar()); instances.put("fie", new FieBar()); } // There is also the option of using java.lang.reflect stuff here public static Bar forName(String name) { return (Bar)(instances.get(name)); } // Maybe you want to implement a NullObject for a default return value } // Bar.java - superclass and subclasses package barpkg; // important! abstract public class Bar { // or interface // Code outside the package sees this declaration. // Constructors are no-arg, and public by default // But since the *classes* aren't public, only the factory gets to call the constructors. abstract public void twiddle(); } // All these classes can go in the same file if you like. class FooBar extends Bar { // not public! public void twiddle() { doNothing(); } } class FoeBar extends Bar { public void twiddle() { doSomething(); } } class FoeBar extends Bar { public void twiddle() { doSomethingElse(); } } class FoeBar extends Bar { public void twiddle() { doYetAnotherThing(); } } // Caller.java - for usage example package callerpkg; // Outside the singleton hierarchy+factory package public class Caller { public void doEverything() { Bar b; String names[] = {"foo", "fee", "fie", "foe"}; for (int i = 0; i < names.length; i++) { b = Bars.forName(names[i]); b.twiddle(); } } public void DoesntWork() { // FooBar f; - can't see class; doesn't compile // Bar b = new FooBar(); - can't see constructor; doesn't compile try { Class.forName("barpkg.FooBar").newInstance(); } catch (Exception e) {} // will get an IllegalAccessException try { Class.forName("barpkg.Bar").newInstance(); } catch (Exception e) {} // will get an InstantiationException } }