singleton模式是Gof提出的23中模式之一,也称为单例模式,那么简单说一下,什么叫单例模式呢?
通常我们创建类的对象是使用new Object(),然后就调用该对象里面的方法,那么当我们多次使用new Object()的话,会对系统资源造成一种浪费,当然.net内部已经有垃圾回收机制可以处理这种浪费。当然我们并不会再程序里面多次使用new Object(),但是,作为一个类的设计者,我们需要负什么责任,除了让别的模块可以调用使用之外,我们的设计还需要一种规范,这也是OO里面的规范,singleton模式在这里派上了用场。

singleton模式的意图:确保一个类只能拥有一个实例,并保证逻辑的正确性以及良好的效率,并提供一个该实例的全局访问点。
singleton模式类型:单线程singleton,多线程singleton
singleton思路:要让使用者只能使用一个实例的话,那么必须绕过常规的公有缺省构造器

singleton代码:

 1     public class singleton
 2     {
 3         private static singleton instance;
 4         private singleton() { }
 5         public static singleton Instance
 6         {
 7             get
 8             {
 9                 if (instance == null)
10                 {
11                     instance = new singleton();
12                 }
13                 return instance;
14             }
15         }
16     }

第4行:利用私有构造函数绕开系统自带的缺省公有构造函数,这样就使类的外部不可以直接使用new实例化对象
第5行:提供一个静态的公有属性,供类外部调用
第9行:在这里可能存在BUG,当有两个线程同时操作公有属性时,常规的话应该返回两个一样的实例,但是假如当第一个实例还未来得及创建时,第二个线程又访问了它,显然也会执行              new singleton()这个语句,那么这两个对象的引用就不一样了,可以使用object.ReferenceEquals测试一下对象的引用是否一样。因此,给大家提供多线程方案,请看下面代码

 

 1     public class singletons
 2     {
 3         private static volatile singletons instances = null;
 4         private static object lockHelper = new object(); 
 5         private singletons() { }
 6         public static singletons Instance
 7         {
 8             get
 9             {
10                 if(instances==null)
11                 {
12                     lock (lockHelper)
13                     {
14                         if(instances==null )
15                         {
16                             instances = new singletons();
17                         }
18                     }
19                 }
20                 return instances;
21             }
22         }
23     }

 

显然看起来与单线程singleton差不多,多了volatile 修饰符,还有一个Object对象,接下来跟大家解释使用这些其中的缘由
volatile 修饰符
假如我定义两个变量和两个属性

 int a;
 
volatile int b;
 
public int GetFirst
 {
     
get { return a; }
 }
 
public int GetSecond
 {
     
get { return b; }
 }

 

GetFirst会得到当前线程中a的值,而多个线程就会有多个a的变量拷贝,而且这些拷贝之间可以互不相同,换句话说,另一个线程可能改变了它线程内的a值,而这个值和当前线程中的a值不相同,那么就造成线程冲突了。
那么再来看看b,因为volatile 修饰的变量不允许有不同于“主”内存区域的变量拷贝,换句话说,一个变量经volatile 修饰后在所有线程中都是同步的;任何线程改变了它的值,所以其他线程立即获取到了相同的值,当然加了volatile 修饰的变量存储时会比一般变量消耗的资源要多一点。

Object对象锁
对象锁可以保证Lock里面的代码只能同时让一个线程执行,所以确保了一个对象只存在一个实例。

同样的需求可以有不同的方法实现,以下是另外一种实现singleton模式的代码,代码更简单,不够有缺陷,请看

 

 public class singletonss
 {
     
public static readonly singletonss Instance = new singletonss();
     
private singletonss() { }
 }

 

首先定义一个静态的只读实例,当然也需要私有构造器绕过缺省构造器,这样子也可以保证多线程里也只诞生一个对象实例,因为.Net类型初始化机制保证只有一个线程执行了静态构造器。当然这么少的代码也可以实现singleton,但是静态构造器不支持参数,也不能重构,因为在.Net机制里面只允许一个类拥有一个静态构造器而且是私有的,外部不能调用只能供系统调用,所以我们不能使用参数。

 

总结 :设计模式对我来说就像是政治课,很多都看不懂其中的缘由,但是有一点敢保证就是它肯定是正确的,我也是刚接触到设计模式,很多东西都不懂,不过通过实践,多敲敲代码,会明确很多,甚至有些还要用反编译看源码才知道里面一些缘由,这也是就是封装代码的缺陷吧,你会使用它但是你不懂得它的内部机制,不过现在还好,网络上有很多资源可以学习,微软也有很多讲师讲解.net的内部机制,让我们的学习更进一层。(强烈推荐iReaper--MSDN Webcasts视频下载工具)

 

 

posted on 2010-12-02 20:02  祯の少  阅读(1070)  评论(1编辑  收藏  举报