单例模式的定义为:保证一个类只有一个实例,并且提供一个全局的访问入口。
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章节。