为什么要使用单件模式(Why use Singleton pattern)
我以前开发过一个OA系统,里面有个工作流子系统。工作流是一个很复杂的系统,采用CS架构开发最好了,但是现在要采用BS架构。BS架构对状态的处理是一个弱点。这个任务流系统需要实现任务流自定义,就是用户可以设计一个流程。谁执行,谁审核,通知谁都是自定义的。那么在定义这个流程的时候不可能一个页面就定义完,需要在多个页面之间传递数据。我们最先想到的办法就是采用Session或者Application。但是它们的不稳定性,他们的会释放都是让人头疼的。还有一个问题,如果系统运行了很久,一个企业每天都有很多工作流需要处理,那么工作流这个表的数据就是近百万条,而查找、修改工作流需要跨多个表的查询操作。并发多的时候难免造成数据库服务器死锁或者Down机。这个时候我就想起了CS架构的程序,所有的对象都不释放,随时可以访问,可以启动一个线程,选择一个合适的时机进行数据库读写。而BS架构很难做到。
那么采用BS架构就无法有效的保存状态了吗?答案是肯定可以。将我们原来的CS架构的工作流系统拿过来,编写全局的唯一的对象将整个系统运行起来。那么整个系统就是用这个全局的唯一的标识符来访问,他不会因为Web页面的释放而释放。说白了就是采用了单件模式。
真实世界里有很多单件模式,比如一说中国,肯定是说亚洲洲的中国,世界上只有一个中国,因此中国就是一个单件模式的例子。
什么是单件模式(What is Singleton pattern)
单件模式(Singleton Patterns)顾名思义就是一个类只有一个实例。也就是世界上只有一个中国,中国就是唯一的实例。这个事例可以有多个引用,比如说“China”可以引用中国,“中国”也可以引用中国。
如何实现单件模式(How to use Singleton pattern)
1、UML图
2、C#代码
2.1普通实现,首先将类的构造函数声明成私有的,然后生命一个静态的引用。这就是最简单的单件模式。
/// 单件模式,线程不安全
/// </summary>
public class Singleton1
{
/// <summary>
/// 构造函数私有防止被外界实例化
/// </summary>
private Singleton1()
{ }
private static Singleton1 _Instance;
/// <summary>
/// 先判断字段是否为空,然后实例化或者返回
/// </summary>
public static Singleton1 Instance
{
get
{
if (_Instance == null )
{
_Instance = new Singleton1();
}
return Singleton1._Instance;
}
set
{
Singleton1._Instance = value;
}
}
}
看过了上面的代码,能发现有什么问题呢?那就是线程不安全,当地多个线程同时执行if (_Instance == null)语句的时候,都会new一个新对象,这样就不能保证是单件。
那么下面就是线程安全的单件模式
2.2线程安全但是惰性
/// 单件模式,线程安全,但是惰性的
/// </summary>
public class Singleton2
{
private Singleton2()
{ }
/// <summary>
/// 直接实例化
/// </summary>
private static Singleton2 _Instance = new Singleton2();
/// <summary>
///
/// </summary>
public static Singleton2 Instance
{
get
{
return Singleton2._Instance;
}
set
{
Singleton2._Instance = value;
}
}
}
从上面的代码,可以看到,private static Singleton2 _Instance = new Singleton2();不论使用不使用该对象,这一句代码一定要执行的。因此我们说这种实现是惰性的。如果我们想采用不惰性的实现,请看下面的代码
2.3线程安全不惰性
{
private Singleton3()
{ }
private static Singleton3 _Instance;
/// <summary>
/// 由于在.NET中无法锁定空对象因在这里声明一个对象专门为了锁
/// </summary>
private static object _TheLock;
public static Singleton3 Instance
{
get
{
// 首先判断单件是不是空
if (_Instance == null )
{
// 锁定
lock (_TheLock)
{
// 再次判断,请思考为什么要再次判断呢?
if (_Instance == null )
{
_Instance = new Singleton3();
}
}
}
return Singleton3._Instance;
}
set
{
Singleton3._Instance = value;
}
}
}
为什么要判断两次才行呢?在.NET环境下,不能锁定空对象。因此我们需要一个辅助对象来实现锁功能。但是锁住的对象不是我们需要的对象,因此要判断两次。
在什么场合使用单件模式(Where can use Singleton pattern)
单件模式的应用场合太多了。本人只能在这里发表一些愚见。根据我的开发经验,单件模式一般使用在根对象上。比如我写一个Word,那么表示Word应用程序的根对象采用单件模式。编写一个WindowsService,这个这个服务用一个对象管理起来,这个对象采用单件模式。
几点思考
1、单键模式就是类只有一个实例,不是说整个系统里就一个实例,在.NET环境下表示一个应用程序域内就一个对象。
2、您可以写一个单件模式的类,部署在两个应用程序中,一个控制台的。一个Winforms的,修改一个对象的值,您可以发现连个应用程序中的对象不是一个。
源码下载(Download code)