您的位置:首页 > 其它

设计模式 之 单件模式

2008-09-26 17:53 344 查看
单件模式

一、意图
“单件”,从字面上理解也就是“一个零件”。我们平常说的单件模式,也是说要求我们整个应用程序中“有且只有”一个对象实例,这个对象实例为整个应用程序所共享,我们不希望也没必要创建多个这样的对象实例。
既然,单件模式可以做到保证应用程序中有且只有一个对象实例,那么单件模式当然也可以保证应用程序有且只有N个对象实例或最多只有N个对象实例。
二、要点
1、怎样保证有且只有一个实例对象
要解决的问题:
1、阻止客户代码随意创建对象(解决只有一个对象的问题)
2、怎样创建对象(解决要有一个对象的问题)
一般,我们要获取一个对象实例常用的方式是通过new关键字来硬编码创建对象实例。在面向对象中我们一般是先写个class,然后new对象实例时,通过调用class中的构造方法来实例话对象,这是一种很简单也很直接的方式。在这种情况下我们必须把class中相应的构造方法指定public访问权限,这样我们通过new关键字创建对象实例时,才能执行到相应的构造方法。下面是一个错误的实例:
由一个ClassA类定义如下:
public class ClassA
{
private ClassA() { } //注意此处ClassA构造方法访问权限为private
}
客户程序中创建ClassA对象实例:
ClassA a = new ClassA();//该语句会出编译错误,因为不能执行到该类的构造方法。
也就是说,我们可以通过将类的构造方法访问权限设置为private来阻止其他程序创建该类的对象实例。
所以我们的单件模式代码可以初步写为:
public class Singleton
{
private static Singleton _instance;//static申明的成员变量_instance,作用于整个应用程序域
private Singleton() { }
}
那么,我们怎样创建对象实例,让客户程序能够获取到Singleton对象实例:
public class Singleton
{
private static Singleton _instance;
private Singleton() { }
public static Singleton GetInstance() //客户程序通过GetInstance()来获取Singleton对象实例
{
if(_instance==null)
{
_instance = new Singleton();//在类的内部,实例化对象实例
}
return _instance;
}
}
以上是一个最简单的单件模式,当然有待改进的地方。在多线程下,这样的实现方式可能会导致Singleton对象实例不唯一。
如:有A、B两个线程,当A线程将要执行GetInstance()方法中的 _instance = new Singleton() 语句而又没有执行完时,这时,_instance还为null。正巧,B线程也进入了GetInstance()方法,开始执行if(_instance==null)语句,因为A线程还没有创建好Singleton实例,所以if(_instance==null)将返回true值给B线程,B线程也将会执行到_instance = new Singleton(),如果还有C线程也跟B线程一样,那么将会创建更多的Singleton对象实例。很快我们会想到线程锁:
public class Singleton
{
private static object _lockObj = new object();//锁对象
private static Singleton _instance;
private Singleton() { }
public static Singleton GetInstance() //客户程序通过GetInstance()来获取Singleton对象实例
{
lock( _lockObj )
{
if( _instance==null )
{
_instance = new Singleton();//在类的内部,实例化对象实例
}
return _instance;
}
}
}
但是,每次我们通过GetInstance()访问Singleton实例时都要lock一下,给线程加锁是比较耗资源的,改进如下:
public class Singleton
{
private static object _lockObj = new object();//锁对象
private static Singleton _instance;
private Singleton() { }
public static Singleton GetInstance() //客户程序通过GetInstance()来获取Singleton对象实例
{
if( _instance==null)//当_instance不为null时,以后的访问将不会被加锁
{
lock( _lockObj )
{
if( _instance==null )
{
_instance = new Singleton();//在类的内部,实例化对象实例
}
}
}
return _instance;
}
}
当然,还可以通过静态初始化来避免多线程下创建多个实例的问题,实现如下:
public class Singleton
{
private static Singleton _instance = new Singleton();
private Singleton() { }
public static Singleton GetInstance() //客户程序通过GetInstance()来获取Singleton对象实例
{
return _instance;
}
}
也可以通过静态构造方法来初始化话_instance对象,静态构造方法或类静态变量直接赋值都没有多线程下多次实例化的问题。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: