您的位置:首页 > 其它

singleton模式及static成员数据的继承

2008-08-25 14:41 337 查看
在软件工程领域,Singleton是一种将对象的实例限制为只有一个的一种模式。当系统的所有处理只需要某个对象的一个实例的时候可以适用这种模式。通常情况下,实例存在的越少(最好是一个)系统的性能越好。针对于Singleton的反模式是使用全局变量。
在wikipedia上Java的标准实现是:
public class Singleton
{
// 通过私有化构造方法,防止在Singleton类之外构造类的实例。
private Singleton() {}

/**
* SingletonHolder 在Singleton.getInstance()第一次调用的时候被初始化。
*/
private static class SingletonHolder
{
private final static Singleton INSTANCE = new Singleton();
}

public static Singleton getInstance()
{
return SingletonHolder.INSTANCE;
}
}

或者更常见的是:

public class Singleton {
private final static Singleton INSTANCE = new Singleton();

// 通过私有化构造方法,防止在Singleton类之外构造类的实例。
private Singleton() {}

public static Singleton getInstance() {
return INSTANCE;
}
}

关于Singleton的说明第一,必须保证在类的外部不能调用构造方法。
在默认无构造方法的情况下,Java编译器会给类加上一个没有参数的共有的(Public)构造方法(默认构造方法),有构造方法的情况下Java编译器保留定义的构造方法。所以在使用Singleton的时候,如果有构造参数则需要将访问修饰符改为private的,没有构造参数的情况下,需要添加一个私有的默认构造方法。私有的默认构造方法参看上述代码。

private Singleton() {}

第二,必须有一个类的实例
为了避免在累得外面实例化类,所以在第一步中将构造参数设置为了私有,所以只能在类的内部实例化,参看上述代码。

private final static Singleton INSTANCE = new Singleton();

第三,在类的外部必须能够访问到第二步中创建的实例。
由于类不能被实例化,所以获取类内部的实例的方法必须为静态的。参看代码:

public static Singleton getInstance() {
return INSTANCE;
}
这个时候也明白了第二步中,INSTANCE实例为什么是static的了,final只是为了强调INSTANCE被初始化之后即不可改变,更见强调了singleton的含义。

关于Singleton的一些变化如果一个Singleton类需要初始话怎么办呢?有两个方法第一种方法,添加静态代码段

public class Singleton {
private final static Singleton INSTANCE = new Singleton();

static{
// 在这里初始化Singleton的实例INSTANCE
}

// 通过私有化构造方法,防止在Singleton类之外构造类的实例。
private Singleton() {}

public static Singleton getInstance() {
return INSTANCE;
}
}

第二种方法,在getInstance的时候初始化
public class Singleton {
private static Singleton INSTANCE;

// 通过私有化构造方法,防止在Singleton类之外构造类的实例。
private Singleton() {}

public static Singleton getInstance() {
if(INSTANCE == null) {
INSTANCE = new Singleton();
//初始化代码
}
return INSTANCE;
}
}

另种方法采用的原则是,如果肯定会使用到这个实例,可以采用第一种方法;如果可能使用到这个实例,可以使用第二种方法。

Singleton初始化异常处理 Singleton实例初始化的时候可能会出现一些异常,通常情况下可以不考虑,如果使用上述的第一种方法,实例化时发生在代码装载的时候,除了日志不可能给用户反馈。如果使用第二种方法,可以在用户调用的时候处理,可以在getInstance方法接口添加抛出异常便于用户处理。
所以如果Singleton初始化会抛出异常,且此类异常需要客户处理的时候需要使用上述的第二种方法。

以上是引用某人的一遍文章,讲得挺不错的。原文地址:http://www.diybl.com/course/3_program/java/javajs/200797/70127.html
还有就是关于static变量的继承问题(也就是说,如果父类声明了一个静态变量,那么子类继承后是共享同一个地址还是另外复制一份),这里介绍一个测试的结果就可以得到结论了:/article/5845038.html

DP中提出的singleton模式不可以被用来当做继承基类的,每次要按照singleton的规则来设计一个singleton类是很痛苦的事,特别是当程序中singleton频繁出现的时候。MCD中的singleton也是外包的,这是一个singleton被用做基类的实现,不过跟语言相关了,用在C++中是没有问题的。

要想子类能够继承singletonbase基类并且子类也可以成为singleton模式,那么可以采用模板的形式来做

下面是该模板类的实现:

template<class SubClass>
class Singleton
{
protected:
static SubClass *_instance;
public:
static SubClass * getInstance()

{
if(!_instance)
_instance = new SubClass();

return _instance;
}
protected: //必须要声明为protected,不然子类会构造不出来
Singleton(){} //基类构造函数必须要有所定义

~Singleton(){ delete _instance; _instance = 0; }
};

template <class SubClass>
SubClass * Singleton<SubClass>::_instance = new SubClass();

使用情况很简单:

class Machine : public Singleton<Machine> {...};

client 如果这样:Machine obj;

或者:Machine *pMch = new Machine;

应该这样用Machine::getInstance()->(Machine的方法)

Singleton都会抛出运行期异常,曾经有人提出过能不能在编译期识别出这些异常情况来,我认为是没有办法的,至少我没有想到过办法,当然,或许路过的各位高手有更好的解决办法,请指出。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: