Java Singleton Package

last modified: November 20, 2004

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

Loading...