1:所谓能看懂并不一定理解,理解并不一定能做,能做并一定应用的好.虽然已经有很多园友写过相关的文章,但是我自己并没有写过,自己把自己的理解通过代码的形式表现出来也是一种自我提高.
2:设计模式是编程人员能力的一方面,经典的东西并不会因为时间的流逝而失宠.
单件模式特点:
1 :单件类只可有一个实例。
2 :单件类必须自己创建自己这惟一的实例。
3 :单件类必须给所有其他对象提供这一实例。
创建单件常用的方式:
1:静态变量法,也叫惰性实例化;
2:双重锁定。
第一:静态变量法非常好理解,.net的运行机制决定了静态变量可以形成单件,静态变量是一个存储在内存中的变量。它的机制可以保证同一时间只会存在一个变量。为此我们非常容易的可以写出这样的程序:
1: 这种对于单线程运行的程序来说是绝对没有问题的,例如运行一个 asp.net程序,一般网站都基本用不到多线程,所有上面的例子就足够满足。但是如果是多线程呢?如果同时有两个线开始判断 instance==null,如果此时都为真,则创建了两上实例,这样就违背了单件的原则。为此可进行下修改:
Code
非线程安全的单件#region 非线程安全的单件
/**//// <summary>
/// 定义自身的静态变量实例,默认值为null
/// </summary>
private static Singleton instance = null;
/**//// <summary>
/// 私有构造函数
/// 之所有不是public类型的,因为是为了避免发生new Singleton()产生更多的实例
/// </summary>
private Singleton()
{ }
/**//// <summary>
/// 生成实例方法
/// </summary>
/// <returns></returns>
public static Singleton getInstance()
{
//如果实例没有被初始化则实例化变量
if (instance == null)
{
instance = new Singleton();
}
return instance;
}
#endregion
2:这种方法在程序初始化时对类实例进行了初始化,利用静态变量以及私有构造方法完成了单件的生成。之所以称这种方式是惰性实例化,是因为无论你是否调用这个实例,它都会被创建。
Code
线程安全的单件(静态变量方法)#region 线程安全的单件(静态变量方法)
/**//// <summary>
/// 定义自身的静态变量实例,在程序运行时初始化变量
/// instance被申请成readonly,也是为了避免给实例重新赋值.
/// </summary>
private static readonly Singleton instance = new Singleton();
/**//// <summary>
/// 私有构造函数
/// 之所有不是public类型的,因为是为了避免发生new Singleton()产生更多的实例
/// </summary>
private Singleton()
{ }
/**//// <summary>
/// 生成实例方法
/// </summary>
/// <returns></returns>
public static Singleton getInstance()
{
return instance;
}
#endregion
第二:双重锁定:我们可以对方法1进行下改造,它的缺点就是非线程安全,既然有缺点当然就要改正了。
3: 这个方法是线程式安全的单件模式,但是它每次生成单件的时候都要给对象加锁,这样也是一种性能消耗.上面说了有缺点就要改,这个方法当然也不例外:
Code
线程安全的单件(双重锁定方法1:线程安全但性能较差)#region 线程安全的单件(双重锁定方法1:线程安全但性能较差)
/**//// <summary>
/// 定义自身的静态变量实例,默认值为null
/// </summary>
private static Singleton instance = null;
/**//// <summary>
/// 创建一个object对象,同样它也是静态只读,用来实现锁定功能
/// </summary>
private static readonly object olock = new object();
/**//// <summary>
/// 私有构造函数
/// 之所有不是public类型的,因为是为了避免发生new Singleton()产生更多的实例
/// </summary>
private Singleton()
{ }
/**//// <summary>
/// 生成实例方法
/// </summary>
/// <returns></returns>
public static Singleton getInstance()
{
//取得实例的时候先锁定对象,然后判定是否存在
lock (olock)
{
//如果实例没有被初始化则实例化变量
if (instance == null)
{
instance = new Singleton();
}
return instance;
}
}
#endregion
4: 这个方法在生成的实例的时候,先判断是否为空,如果不为空则不对对象进行加锁操作直接返回对象实例。同时这种双重锁定对比静态方法来看,有一个优势就是它的实例化延迟到类中,只有调用此类的实例时它才会生成实例.。
Code
线程安全的单件(双重锁定方法2:线程安全而且性能优越)#region 线程安全的单件(双重锁定方法2:线程安全而且性能优越)
/**//// <summary>
/// 定义自身的静态变量实例,默认值为null
/// instance被申请成readonly,也是为了避免给实例重新赋值.
/// </summary>
private static Singleton instance = null;
/**//// <summary>
/// 创建一个object对象,同样它也是静态只读,用来实现锁定功能
/// </summary>
private static readonly object olock = new object();
/**//// <summary>
/// 私有构造函数
/// 之所有不是public类型的,因为是为了避免发生new Singleton()产生更多的实例
/// </summary>
private Singleton()
{ }
/**//// <summary>
/// 生成实例方法
/// </summary>
/// <returns></returns>
public static Singleton getInstance()
{
if (instance == null)
{
//取得实例的时候先锁定对象,然后判定是否存在
lock (olock)
{
//如果实例没有被初始化则实例化变量
if (instance == null)
{
instance = new Singleton();
}
}
}
return instance;
}
#endregion
小结:上面都是常规的单件模式,其实并不是所有的情况都如上面一样。在抽象工厂的应用中经常结合单件模式来应用,使得工厂实例是唯一的。在上一篇 用抽象工厂模式武装新闻组件 中,我用上了抽象工厂,当时在抽象工厂类实例的生成上并没有结合单件模式,所在在这想改造一下。我的程序思路是这样的,有一个抽象工厂基类AbstractFactoryClass,它包含一个public static AbstractFactoryClass GetInstance()方法,作用是生成它的派生类的实例,而这个生成过程是通过反射来完成。这两个派生类分别是:AbstractFactory_China,AbstractFactory_US.这种情况下要想直接返回AbstractFactoryClass的实例是不可能的,因为它是抽象类,不能直接new AbstractFactoryClass()。先看下这三个类的类图:
代码如下:代码因为基类是抽象类所有没有上面常规程序中的私有构造函数,这种生成抽象工厂类派生类实例的案例并不适用于静态方法构造单件的情况,因为你不能直接通过new的方式来初始化类实例。
Code
//把抽象类设置成静态变量,避免多次加载程序集
private static AbstractFactoryClass instance=null ;
/**//// <summary>
/// 创建一个object对象,同样它也是静态只读,用来实现锁定功能
/// </summary>
private static readonly object olock = new object();
public static AbstractFactoryClass GetInstance()
{
//应用双重锁定来产生工厂单件对象
if (instance == null)
{
lock (olock)
{
if (instance == null)
{
//取得当前工厂名称
string factoryName = ConfigurationSettings.AppSettings["factoryName"].ToString();
if (factoryName != "")
instance = (AbstractFactoryClass)Assembly.Load("AbstractFactoryCompent").CreateInstance(factoryName);
else
instance = null;
}
}
}
return instance;
}
我老生常谈的理由有二:
1:所谓能看懂并不一定理解,理解并不一定能做,能做并一定应用的好。虽然已经有很多园友写过相关的文章,但是我自己并没有写过,自己把自己的理解通过代码的形式表现出来也是一种自我提高。
2:设计模式是编程人员能力的一方面,经典的东西并不会因为时间的流逝而失宠。
注:
1:本文相关内容有部分摘自网络.
2:引用:http://terrylee.cnblogs.com/archive/2005/12/09/293509.html