Java Singleton Package

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:

This approach is flexible: the factory is made responsible for making sure that there is only one instance of each class. So this is not so much a SingletonPattern as a general creation-control pattern.

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 } }


EditText of this page (last edited November 20, 2004) or FindPage with title or text search