23.4. 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.

Singleton

Context/Problem

Exactly one instance of a class is allowed—it is a “singleton.” Objects need a global and single point of access.

Solution

Define a static method of the class that returns the singleton.


For example, Figure 23.5 shows an implementation of the Singleton pattern.

Figure 23.5. The Singleton pattern in the ServicesFactory class.


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:

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

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 SingletonClass.getInstance() in order to obtain visibility to the singleton instance, and then send it a message, such as SingletonClass.getInstance().doFoo(). It's hard to beat the feeling of being able to globally doFoo.

UML Shorthand for Singleton Access in Interaction Diagrams

A UML notation that implies—but does not explicitly show—the getInstance message in an interaction diagram is to add a «singleton» stereotype to the instance, as in Figure 23.6. This approach avoids having to explicitly show the (uninteresting) getInstance message to the class before sending a message to the singleton instance.

Figure 23.6. Implicit getInstance Singleton pattern message indicated in the UML with a stereotype.


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:

							public static synchronized ServicesFactory getInstance()
							{
							if ( instance == null )
							{
							// critical section if multithreaded application
							instance = new ServicesFactory();
							}
							return instance;
							}
						

On the subject of lazy initialization, why not prefer eager initialization, as in this example?

							public class ServicesFactory
							{
							// eager initialization
							private static ServicesFactory instance =
							new ServicesFactory();
							public static ServicesFactory getInstance()
							{
							return instance;
							}
							// other methods...
							}
						

The first approach of lazy initialization is usually preferred for at least these reasons:

  • 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.

Another common Singleton implementation question is: Why not make all the service methods static methods of the class itself, instead of using an instance object with instance-side methods? For example, what if we add a static method called getAccountingAdapter to ServicesFactory. But, an instance and instance-side methods are usually preferred for these reasons:

  • 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.

The Singleton pattern is often used for Factory objects and Facade objects—another GoF pattern that will be discussed.

Related Patterns


..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.191.199.227