单例模式的定义为:保证一个类只有一个实例,并且提供一个全局的访问入口。
Ensure a class only has one instance, and provide a global point of access it.
虽然说,单例模式在所有的模式当中算是比较简单的一个,但是如果牵扯到线程安全问题,似乎没有那么简单。
本文参考《Head First》和《Design Patterns》举例说明单例模式的使用方法和注意事项。
为什么我们不用全局变量,而使用单例呢?
原因大致有四点,第一,全局变量不是OO设计所提倡的;第二,使用全局变量的形式并不能阻止用户创建多个类的实例;第三,对全局变量不能高效地使用lazy initialization。
当然如果静态类是self-constraint,当然可以使用,但是好多时候,对象是需要依赖外部状态的,并且静态类是不能够被继承的。
《Head First》中不提倡subclass单例,因为Singletons are meant to be used sparingly.
《Design Patterns》中,subclass单例后,可以不改变使用着的代码作为单例模式的一个优势来介绍,而且单例模式可以不“单例”,可以创建多个实例。
以下C++代码,则实现了如此功能,当然生成多个实例的单例模式有很多弊端,在本例中,子类的必须实例化才能够在registry中注册,因此违背了lazy initialization的原则。
// 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();本例中忽略了线程安全等问题。
在java中倒是可以很简单的写出线程安全的单例模式。
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; } }关于此处几个关键字,具体可以参见《Header First Design Patterns》介绍singleton章节。