Everyone's favorite, The Singleton Pattern, is probably the most overused and least well implemented design pattern.
There are at least seven different variations on the singleton implementation in Java, some are detailed in Head First Design Patterns, some are documented in Joshua Bloch's awesome book Effective Java, and some I've found along the way on the web.
Not all of the variations can be implemented in ColdFusion, but lets list them and pick the best one to code in CFML.
None of them can be implemented in ColdFusion, but lets list them and see why.
Lazily created Singleton with static factory method
Introduced as the first singleton example in Head First Design Patterns. It isn't thread safe.
public final class Singleton { private static Singleton instance; private Singleton() { } public static Singleton getInstance() { if (null == instance) { instance = new Singleton(); } return instance; } }
Synchronized lazily created Singleton with static factory method
Introduced as the second example in Head First, it is thread safe but uses a computationally expensive synchronized method.
public final class Singleton { private static Singleton instance; private Singleton() { } public static synchronized Singleton getInstance() { if (null == instance) { instance = new Singleton(); } return instance; } }
Eagerly created Singleton with static factory method
Detailed as an alternative to synchronizing the getInstance() method in Head First, and presented as a possible implementation in Joshua Bloch's Effective Java. Bloch goes on to note that this implementation and the following implementation can not be made serializable by just adding implements Serializable
. All instance fields would need to be declared transient
and a readResolve() method provided.
public final class Singleton { private static final Singleton INSTANCE = new Singleton(); private Singleton() { } public static Singleton getInstance() { return INSTANCE; } }
Eagerly created Singleton with public final field
Presented by Bloch as an alternative to the above implementation, it's main advantage is that the class definition clearly shows it is a singleton.
public final class Singleton { public static final Singleton INSTANCE = new Singleton(); private Singleton() { } }
Double checked locking
The third and final example in Head First, only synchronizes the first time through the getInstance() method. This implementation of the singleton makes use of the volatile
keyword. In Java versions 1.4 and earlier, volatile
could allow improper synchonization, this implementation is not portable to older JVMs.
public final class Singleton { private volatile static Singleton instance; private Singleton() { } public static Singleton getInstance() { if (null == instance) { synchronized (Singleton.class) { if (null == instance) { instance = new Singleton(); } } } return instance; } }
The solution of Bill Pugh
The solution of Bill Pugh uses a nested class to be as lazy as possible, is thread safe without using synchronized
or volatile
, and is usable with all JVM versions.
public final class Singleton { private Singleton() { } private static class SingletonHolder { private static final Singleton INSTANCE = new Singleton(); } public static Singleton getInstance() { return SingletonHolder.INSTANCE; } }
Enum Type
Since version 1.5, Java has had support for enums. The final implementation in Effective Java uses an enumerated type with one element. This is equivalent to the public final field implementation but takes care of serialization automatically, and guarantees only a single instance.
public enum Singleton { INSTANCE; }
From Effective Java:
"a single-element enum type is the best way to implement a singleton."
ColdFusion
ColdFusion doesn't support enum types or nested CFCs, so those are out straight away.
Lazily created Singleton with factory method
A lazily created Singleton fails to be initialized because the component can't see its own private constructor.
LazyFactoryMethod/Singleton.cfc
<cfcomponent output="false" > <cffunction access="private" returntype="Singleton" name="init"> <cfreturn THIS> </cffunction> <cffunction access="public" returntype="Singleton" name="getInstance"> <cfif NOT isDefined("VARIABLES.INSTANCE")> <cfset VARIABLES.INSTANCE = createObject("component", "Singleton").init()> </cfif> <cfreturn VARIABLES.INSTANCE> </cffunction> </cfcomponent>
Eagerly created Singleton with factory method
An eagerly created Singleton with a factory method goes in to a self referential loop and fills up the stack.
EagerFactoryMethod/Singleton.cfc
<cfcomponent output="false" > <cfset VARIABLES.INSTANCE = createObject("component", "Singleton").init()> <cffunction access="private" returntype="Singleton" name="init"> <cfreturn THIS> </cffunction> <cffunction access="public" returntype="Singleton" name="getInstance"> <cfreturn VARIABLES.INSTANCE> </cffunction> </cfcomponent>
Eagerly created Singleton with a public field
Same as with the previous eagerly created Singleton, a java.lang.StackOverflowError
is thrown on instantiation.
EagerField/Singleton.cfc
<cfcomponent output="false" > <cfset THIS.INSTANCE = createObject("component", "Singleton").init()> <cffunction access="private" returntype="Singleton" name="init"> <cfreturn THIS> </cffunction> </cfcomponent>
So ColdFusion can't create real singletons, how bad does that suck?
Source Code
- Head First Singleton ColdFusion Builder Project - headfirstsingleton.zip