.NET2.0设计模式 (.NET 2.0 Patterns) 1 -- 单件模式(Sington Patterns)

为什么要使用单件模式(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>
    
/// 单件模式,线程不安全
    
/// </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>
    
/// 单件模式,线程安全,但是惰性的
    
/// </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线程安全不惰性

    public class Singleton3
    {
        
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)

下载

返回目录

posted @ 2009-01-04 21:20  陈大杰  阅读(561)  评论(3编辑  收藏  举报