Singleton
中文名称
单件。
意图
保证一个类只有一个实例,并且提供一个全局存取点。问题
应用需要且只需要一个对象的一个实例。此外,延迟初始化和全局存取是必需的。讨论
对于某个类,无论是创建,初始化,存取还是执行,确保只有一个实例。把实例作为一私有静态数据成员声明,提供一个公有静态成员函数封装所有初始化代码,提供对实例的存取。
当需要单独实例的引用时,客户调用存取函数(使用类名::操作)。
Singleton仅在以下三个标准都满足时被考虑:
- 单独实例的拥有者难以合理分配。
- 期望延迟初始化。
- 没有提供全局存取。
Singleton模式可以扩展以支持特定数目的实例。
“静态成员函数存取”方法不支持Singleton类的子类化。
删除一个Singleton类/对象不是一个可有可无的问题。
示例
美国总统是一个Singleton。美国宪法指定了怎样选举总统,限制了此职位的期限,定义了连任顺序。因此,任何时间最多只有一个现任总统。不管现任总统的个人特性如何,“美国总统”的称号是在职者的全局存取点。
其他看法
Singleton不能解决全局变量问题,它只是保证一个类仅有一个实例的模式。至于全局变量,唯一的好处就是减少名字空间。Singleton比全局变量好的地方是能确认有几个实例在被使用。
解决全局变量的答案不是Singleton模式,而是不要使用。
经验规则
Abstract Factory,Builder和 Prototype在实现中能使用Singleton。Facade通常是Singletons,因为只需要一个Facade对象。
State对象通常是Singleton。
// 讨论:Singleton
//
// 讨论:第一个例子中,一个全局对象需要延迟初始化(需要时再初始化)。
// 这需要所有用户检测,并可能分配指针。
// Singleton提倡让对象自身有职责创建,维护,自身的唯一实例,
// 并提供全局访问点。
#include <iostream.h>
class GlobalClass {
public:
GlobalClass( int v=0 ) {
value_ = v; }
int getValue() {
return value_; }
void setValue( int v ) {
value_ = v; }
private:
int value_;
};
// 初始化GlobalClass类的全局指针
GlobalClass* globalObj = 0;
void foo( void )
{
if ( ! globalObj )
globalObj = new GlobalClass;
globalObj->setValue( 1 );
cout << "foo: globalObj is " <<
globalObj->getValue() << endl;
}
void bar( void )
{
if ( ! globalObj )
globalObj = new GlobalClass;
globalObj->setValue( 2 );
cout << "bar: globalObj is " <<
globalObj->getValue() << endl;
}
void main( void )
{
if ( ! globalObj )
globalObj = new GlobalClass;
cout << "main: globalObj is " << globalObj->getValue() << endl;
foo();
bar();
}
// main: globalObj is 0
// foo: globalObj is 1
// bar: globalObj is 2
// 新的设计:“globalObj”现在是自身类的一个私有静态成员函数。
// 通过公有静态成员函数inst()提供了全局访问点。
// 延缓初始化代码在inst()函数中被封装。
// GlobalClass的构造和析构函数是受保护的,
// 用户不能创建更多的实例,也不能销毁Singleton实例。
class GlobalClass {
public:
int getValue() {
return value_; }
void setValue( int v ) {
value_ = v; }
static GlobalClass* inst() {
if ( ! globalObj_ )
globalObj_ = new GlobalClass;
return globalObj_; }
protected:
GlobalClass( int v=0 ) {
value_ = v; }
~GlobalClass() { }
private:
int value_;
static GlobalClass* globalObj_;
};
GlobalClass* GlobalClass::globalObj_ = 0;
void foo( void )
{
GlobalClass::inst()->setValue( 1 );
cout << "foo: globalObj is " << GlobalClass::inst()->getValue() << endl;
}
void bar( void )
{
GlobalClass::inst()->setValue( 2 );
cout << "bar: globalObj is " << GlobalClass::inst()->getValue() << endl;
}
void main( void )
{
cout << "main: globalObj is " << GlobalClass::inst()->getValue() << endl;
foo();
bar();
}
// main: globalObj is 0
// foo: globalObj is 1
// bar: globalObj is 2
// 讨论:Singleton析构
class GlobalClass;
class SingDest {
public:
SingDest( GlobalClass* s=0 ) {
sing_ = s; }
~SingDest();
void setSing( GlobalClass* s ) {
sing_ = s; }
private:
GlobalClass* sing_;
};
class GlobalClass {
public:
friend class SingDest;
int getValue() { return value_; }
void setValue( int v ) {
value_ = v; }
static GlobalClass* inst() {
if ( ! globalObj_ ) {
globalObj_ = new GlobalClass;
dest_.setSing( globalObj_ ); }
return globalObj_; }
private:
GlobalClass( int v=0 ) {
cout << ":ctor: ";
value_ = v; }
~GlobalClass() {
cout << ":dtor:" << endl; }
int value_;
static GlobalClass* globalObj_;
static SingDest dest_;
};
GlobalClass* GlobalClass::globalObj_ = 0;
SingDest GlobalClass::dest_;
SingDest::~SingDest() { delete sing_; }
void foo( void )
{
GlobalClass::inst()->setValue( 1 );
cout << "foo: globalObj is " << GlobalClass::inst()->getValue() << endl;
}
void bar( void )
{
GlobalClass::inst()->setValue( 2 );
cout << "bar: globalObj is " << GlobalClass::inst()->getValue() << endl;
}
void main( void )
{
cout << "main: globalObj is " << GlobalClass::inst()->getValue() << endl;
foo();
bar();
}
// main: globalObj is :ctor: 0
// foo: globalObj is 1
// bar: globalObj is 2
// main: end
// :dtor:
// 目的:Scott Meyers方法。
// “globalObj”现在是访问方inst()的静态成员。
// 通过声明构造函数非公有强制单实例。
// 因为静态变量实例,析构函数必须是公有的。
// inst()静态方法提供访问。
// C++第一次要求时,对象被分配;然后C++能自动销毁它。
#include <iostream.h>
class GlobalClass {
public:
int getValue() {
return value_; }
void setValue( int v ) {
value_ = v; }
static GlobalClass& inst() {
static GlobalClass globalObj;
return globalObj; }
~GlobalClass() {
cout << ":dtor:" << endl; }
protected:
GlobalClass( int v=0 ) {
cout << ":ctor: ";
value_ = v; }
private:
int value_;
};
void foo( void )
{
GlobalClass::inst().setValue( 1 );
cout << "foo: globalObj is " <<
GlobalClass::inst().getValue() << endl;
}
void bar( void )
{
GlobalClass::inst().setValue( 2 );
cout << "bar: globalObj is " <<
GlobalClass::inst().getValue()<< endl;
}
void main( void )
{
cout << "main: globalObj is " << GlobalClass::inst().getValue() << endl;
foo();
bar();
cout << "main: end" << endl;
}
// main: globalObj is :ctor: 0
// foo: globalObj is 1
// bar: globalObj is 2
// main: end
// :dtor:
// 讨论:Singleton设计模式,支持继承
// 1. 在类中定义一个私有静态属性。
// 2. 在类中定义一个公有静态访问函数。
// 3. 在访问函数中作“延缓初始化”(根据命令创建)。
// 4. 定义所有构造函数受保护或者私有。
// 5. 用户只能使用访问函数来操纵 Singleton。
// 6. 能支持继承,但是不能覆盖静态函数。
// 基类必须被声明为派生类的友元,以访问受保护的构造函数。
#include <iostream>
#include <string>
#include <stdlib.h>
using namespace std;
class Number {
public:
static Number* instance(); // 2. 在类中定义一个公有静态访问函数。
static void setType( string t ) { type = t; delete inst; inst = 0;}
virtual void setValue( int in ) { value = in; }
virtual int getValue() { return value; }
protected:
int value;
Number() { cout << ":ctor: "; } // 4. 定义所有构造函数受保护或者私有。
private:
static string type;
static Number* inst; // 1. 在类中定义一个私有静态属性。
};
string Number::type = "decimal";
Number* Number::inst = 0;
class Octal : public Number { // 6. 能支持继承,但是不能覆盖静态函数。
public:
friend class Number;
void setValue( int in ) {
char buf[10];
sprintf( buf, "%o", in );
sscanf( buf, "%d", &value );
}
protected:
Octal() { }
};
Number* Number::instance() {
if ( ! inst)
// 3. 在访问函数中作“延缓初始化”。
if (type == "octal") inst = new Octal();
else inst = new Number();
return inst;
}
void main( void ) {
// Number myInstance; --- 错误: 不能访问受保护构造函数
// 5. 用户只能使用访问函数来操纵 Singleton。
Number::instance()->setValue( 42 );
cout << "value is " << Number::instance()->getValue() << endl;
Number::setType( "octal" );
Number::instance()->setValue( 64 );
cout << "value is " << Number::instance()->getValue() << endl;
}
// :ctor: value is 42
// :ctor: value is 100