Combining Immutable Singleton and Builder

It is a good idea to use immutable objects where possible to reduce the amount of time you loose debugging because some value is not as expected and trying to find out where it has changed. It is also sensible to use a builder for some class with many members to be initialized at constructing time. It may even make sense to implement your object as a singleton. All these techniques are promoted by Joshua Blochs Effective Java. But can you combine these three items to work together?

First a word of advice: If you use a singleton on an immutable object this object will stay the same from the time of instantiation untill the killing of the VM; think about the livecycle of the VM and your intended lifecycle of your singleton. If they match you are good to go.
It is easy to imagine two of theses three techniques working together:

  • Immutable Singleton
  • Mutable Singleton with a Builder
  • Immutable object with a Builder

So where is the problem with combining all three together? When we implement a class with a builder it is not possible to benefit from the enum type to ensure the singleton pattern (because the default constructor is hidden and final members may be present). We therefore have to take the following approach:

private static ImmutableObject INSTANCE=null;
private ImmutableObject(){
   // hidden default constructor
}
public static ImmutableObject getInstance(){
   if (INSTANCE==null){
      INSTANCE=new ImmutableObject();
   }
   return INSTANCE;
}

If try to combine this with a builder we get the following code:

private static ImmutableObject INSTANCE=null;
private ImmutableObject(IBuilder builder){
   // hidden default constructor
   // initialize the members from the builder
}
public static ImmutableObject getInstance(IBuilder builder){
   if (INSTANCE==null){
      INSTANCE=new ImmutableObject(builder);
   }
   return INSTANCE;
}

So where is the problem, you may ask. The builder is a mutable object. After the first initialisation of INSTANCE this object cannot be changed. If your instance of IBuilder of a second call of getInstance deviates from the first call you get the same instance as the first time which is not what you expected. You only realise that if you look. Therefore it would be a better solution to throw an Exeption if the object to be built by the specifications of the builder are inconsistent with INSTANCE.

private static ImmutableObject INSTANCE=null;
private ImmutableObject(IBuilder builder){
   // hidden default constructor
   // initialize the members from the builder
}
public static ImmutableObject getInstance(IBuilder builder){
   if (INSTANCE==null){
      INSTANCE=new ImmutableObject(builder);
   } else if (/* compare all members with the values of the builder */){
      // The call would result in an identical object
      return INSTANCE;
   } else {
      throw new IllegalStateException("Cannot create an instance of the singleton ImmutableObject, due to data inconstancies.")
   }
}

One final thought: A builder for an immutable class is like mutable Helper: based on the immutable class you can create a builder that can generate a copy of the immutable class. If your immutable class is a singleton this defeats the purpose.

Schreibe einen Kommentar