26.5. Singleton (GoF)
The ServicesFactory raises another new problem in the design: Who creates the factory itself, and how is it accessed?First, observe that only one instance of the factory is needed within the process. Second, quick reflection suggests that the methods of this factory may need to be called from various places in the code, as different places need access to the adapters for calling on the external services. Thus, there is a visibility problem: How to get visibility to this single ServicesFactory instance?One solution is pass the ServicesFactory instance around as a parameter to wherever a visibility need is discovered for it, or to initialize the objects that need visibility to it, with a permanent reference. This is possible but inconvenient; an alternative is the Singleton pattern.Occasionally, it is desirable to support global visibility or a single access point to a single instance of a class rather than some other form of visibility. This is true for the ServicesFactory instance.
Name: | Singleton |
Problem: | Exactly one instance of a class is allowedit is a "singleton." Objects need a global and single point of access. |
Solution: (advice) | Define a static method of the class that returns the singleton. |
Figure 26.6. The Singleton pattern in the
ServicesFactory class.[View full size image]
Notice how a singleton is illustrated, with a '1' in the top right corner of the name compartment.Thus, the key idea is that class X defines a static method getInstance that itself provides a single instance of X.With this approach, a developer has global visibility to this single instance, via the static getInstance method of the class, as in this example:
Since visibility to public classes is global in scope (in most languages), at any point in the code, in any method of any class, one can write
public class Register
{
public void initialize()
{
… do some work …
// accessing the singleton Factory via the getInstance call
accountingAdapter =
ServicesFactory.getInstance().getAccountingAdapter();
… do some work …
}
// other methods…
} // end of class
SingletonClass.getInstance()
in order to obtain visibility to the singleton instance, and then send it a message, such as SingletonClass.getInstance().doFoo() . And it's hard to beat the feeling of being able to globally doFoo !
Implementation and Design Issues
A Singleton getInstance method is often frequently called. In multi-threaded applications, the creation step of the lazy initialization logic is a critical section requiring thread concurrency control. Thus, assuming the instance is lazy initialized, it is common to wrap the method with concurrency control. In Java, for example:
On the subject of lazy initialization, why not prefer eager initialization , as in this example?
public static synchronized ServicesFactory getInstance()
{
if ( instance == null )
{
// critical section if multithreaded application
instance = new ServicesFactory();
}
return instance;
}
The first approach of lazy initialization is usually preferred for at least these reasons:
public class ServicesFactory
{
// eager initialization
private static ServicesFactory instance =
new ServicesFactory();
public static ServicesFactory getInstance()
{
return instance;
}
// other methods...
}
- Creation work (and perhaps holding on to "expensive" resources) is avoided, if the instance is never actually accessed.
- The getInstance lazy initialization sometimes contains complex and conditional creation logic.
Figure 26.7. Implicit
getInstance Singleton pattern message indicated in the UML because of the '1' mark.[View full size image]
- Instance-side methods permit subclassing and refinement of the singleton class into subclasses; static methods are not polymorphic (virtual) and don't permit overriding in subclasses in most languages (Smalltalk excluded).
- Most object-oriented remote communication mechanisms (for example, Java's RMI) only support remote-enabling of instance methods, not static methods. A singleton instance could be remote-enabled, although that is admittedly rarely done.
- A class is not always a singleton in all application contexts. In application X, it may be a singleton, but it may be a "multi-ton" in application Y. It is also not uncommon to start off a design thinking the object will be a singleton, and then discovering a need for multiple instances in the same process. Thus, the instance-side solution offers flexibility.
Related Patterns The Singleton pattern is often used for Factory objects and Facade objectsanother GoF pattern that will be discussed.