The Singleton mode is defined to ensure that a class has only one instance and provides a global access portal.
Ensure a class only has one instance, and provide a global point of access it.
Although the singleton mode is relatively simple among all the modes, it does not seem that simple if it involves thread security issues.
This document describes how to use the singleton mode and precautions by referring to head first and design patterns.
Why do we use Singleton instead of global variables?
There are roughly four reasons. First, global variables are not advocated by OO design. Second, using global variables cannot prevent users from creating instances of multiple classes. Third, lazy initialization cannot be used for global variables efficiently.
Of course, if the static class is self-constraint, it can be used, but in many cases, the object needs to be dependent on the external state, and the static class cannot be inherited.
We do not advocate subclass Singleton in head first because singletons are meant to be used sparingly.
In design patterns, after the subclass Singleton, you can use the Code as an advantage of the singleton mode without changing the code used. In addition, the singleton mode can be different from the singleton mode ", you can create multiple instances.
The following C ++ code implements this function. Of course, the singleton mode for generating multiple instances has many drawbacks. In this example, sub-classes must be instantiated before they can be registered in the registry. This violates the lazy initialization principle.
// singleton.h#ifndef _HEADER_SINGLETON_#define _HEADER_SINGLETON_#include <map>#include <cstddef>#include <iostream>#include <string>using namespace std;class Singleton {public: static void Register(const string& name, Singleton*); static Singleton* Instance(); virtual void tell() { cout << "I am class Singleton" << endl; }protected: static Singleton* Lookup(const string& name);private: static map<string, Singleton*> _registry; static Singleton* _instance;};#endif // _HEADER_SINGLETON_
// singleton.cpp#include "singleton.h"#include <cstddef>#include <cstdio>#include <cstdlib>using namespace std;Singleton* Singleton::_instance = NULL;map<string, Singleton*> Singleton::_registry = map<string, Singleton*>();void Singleton::Register(const string& name, Singleton* singleton) { _registry[name] = singleton;}Singleton* Singleton::Instance() { if (_instance == 0) { const char* singletonName = getenv("SINGLETON"); // user or environment supplies this at startup _instance = Lookup(singletonName); // Lookup returns 0 if there's no such singleton } return _instance;}Singleton* Singleton::Lookup(const string& name) { if (_registry.count(name)) { return _registry[name]; } return NULL;}
#ifndef _HEADER_MY_SINGLETON_#define _HEADER_MY_SINGLETON_#include "singleton.h"class MySingleton : public Singleton {public: virtual void tell() { cout << "I am class MySingleton" << endl; }protected: MySingleton() { Singleton::Register("mysingleton", this); }private: static MySingleton _my_singleton;};#endif // _HEADER_MY_SINGLETON_
#include "mysingleton.h"MySingleton MySingleton::_my_singleton = MySingleton();
In this example, thread security and other issues are ignored.
In Java, the thread-safe Singleton mode can be easily written.
public class ChocolateBoiler { private boolean empty; private boolean boiled; private volatile static ChocolateBoiler uniqueInstance; private ChocolateBoiler() { empty = true; boiled = false; } public static ChocolateBoiler getInstance() { if (uniqueInstance == null) { synchronized (ChocolateBoiler.class) { if (uniqueInstance == null) { uniqueInstance = new ChocolateBoiler(); } } } return uniqueInstance; } public void fill() { if (isEmpty()) { empty = false; boiled = false; } } public void drain() { if (!isEmpty() && isBoiled()) { empty = true; } } public void boil() { if (!isEmpty() && !isBoiled()) { boiled = true; } } public boolean isEmpty() { return empty; } public boolean isBoiled() { return boiled; }}
For more information about the keywords, see the singleton section in Header first design patterns.