Singleton Pattern   «Prev  Next»
Lesson 8Singleton Implementation
ObjectiveWrite a Class that uses the Singleton Pattern.

Write Class that uses the Singleton Pattern

The implementation is the most language-dependent part of the pattern.
  1. Singleton Java
  2. Singleton C++
The trick to the Singleton is threefold:
  1. A nonpublic constructor so that arbitrary instances of the class can not be created.
  2. A field that holds a single unique instance of the class.
  3. A method that returns a reference (Java) or a pointer (C++) to the field.

Gang of Four Patterns
The Singleton pattern is an easy to understand design pattern. Sometimes, there may be a need to have one and only one instance of a given class during the lifetime of an application. This may be due to necessity or due to the fact that only a single instance of the class is sufficient. For example, we may need a single database connection object in an application. The Singleton pattern is useful in such cases because it ensures that there exists one and only one instance of a particular object ever. Furthermore, it suggests that client objects should be able to access the single instance in a consistent manner.


Why Singleton Pattern is Unique

The Singleton design pattern is unique in that it is a strange combination: its description is simple, yet its implementation issues are complicated. This is proven by the abundance of Singleton discussions and implementations in books and magazine articles. The Singleton's description in the GoF book is described simply as:
Ensure a class only has one instance, and provide a global point of access to it.

A singleton is an improved global variable. The improvement that Singleton brings is that you cannot create a secondary object of the singleton's type. Therefore, you should use Singleton when you model types that conceptually have a unique instance in the application, such as Keyboard, Display, PrintManager, and SystemClock. Being able to instantiate these types more than once is unnatural at best, and often dangerous.

Providing a global point of access has a subtle implication—from a client's standpoint, the Singleton object owns itself. There is no special client step for creating the singleton. Consequently, the Singleton object is responsible for creating and destroying itself. Managing a singleton's lifetime causes the most implementation headaches.
This chapter discusses the most important issues associated with designing and implementing various Singleton variants in C++:
  1. The features that set apart a singleton from a simple global object
  2. The basic C++ idioms supporting singletons
  3. Better enforcement of a singleton's uniqueness
  4. Destroying the singleton and detecting postdestruction access
  5. Implementing solutions for advanced lifetime management of the Singleton object
  6. Multithreading issues

We will develop techniques that address each issue. In the end, we will use these techniques for implementing a generic SingletonHolder class template.
There is no "best" implementation of the Singleton design pattern. Various Singleton implementations, including nonportable ones, are most appropriate depending on the problem at hand. This chapter's approach is to develop a family of implementations on a generic skeleton, following a policy-based design. SingletonHolder also provides hooks for extensions and customizations.
By the end of this chapter, we will have developed a SingletonHolder class template that can generate many different types of singletons. SingletonHolder gives you fine-grained control over how the Singleton object is allocated, when it is destroyed, whether it is thread safe, and what happens if a client attempts to use it after it's been destroyed. The SingletonHolder class template provides Singletonspecific services and functionality over any user-defined type.

Static Data and Static Functions is not the same as a Singleton

At first glance, it seems that the need for Singleton can be easily averted by using
  1. static member functions
  2. and static member variables:

class Font { ... };
class PrinterPort { ... };
class PrintJob { ... };

class MyOnlyPrinter{
public:
 static void AddPrintJob(PrintJob& newJob){
  if (printQueue_.empty() &&  printingPort_.available()){
   printingPort_.send(newJob.Data());
  }
  else{
   printQueue_.push(newJob);
  }
 }
private:
// All data is static
static std::queue<PrintJob> printQueue_;
static PrinterPort printingPort_;
static Font defaultFont_;
};

PrintJob somePrintJob("MyDocument.txt");
MyOnlyPrinter::AddPrintJob(somePrintJob);

However, this solution has a number of disadvantages in some situations. The main problem is that static functions cannot be virtual, which makes it difficult to change behavior without opening MyOnlyPrinter's code.
A subtler problem of this approach is that it makes initialization and cleanup difficult. There is no central point of initialization and cleanup for MyOnlyPrinter's data. Initialization and cleanup can be nontrivial tasks. For instance, defaultFont_ can depend on the speed of printingPort_.
Singleton implementations therefore concentrate on creating and managing a unique object while not allowing the creation of another one.

Singleton Pattern - Exercise

Click on the link below to perform the
Singleton Pattern - Exercise