单件模式(Singleton)要求一个类有且仅有一个实例,并且提供了一个全局的访问点。

从概念上来研究一下它的实现,不考虑线程安全

复制代码
 1 public sealed class Singlton
 2 {
 3     static Singlton instance = null;
 4     private Singlton() { }
 6  
 7     public static Singlton Instance
 8     {
 9         get
10         {
11             if (instance == null)
12             {
13                 instance = new Singlton();
14             }
15             return instance;
16         }   
17     }   
18 }
复制代码

上面的实现方式,对于多线程会有问题,因为Singlton 对象可能不指一次被创建,而罪魁祸首就是if (instance == null)这句话,它并不是线程安全的。

如果希望实现线程安全的单件,我们最先想到的应该就是借助lock机制来实现,代码可能是这样:

复制代码
 1 public sealed class Singlton
 2 {
 3     static Singlton instance = null;
 4  
 5     static readonly object o = new object();
 6  
 7     Singlton()
 8     { }
 9  
10     public static Singlton Instance
11     {
12         get
13         {
14             lock (o)
15             {
16                 if (instance == null)
17                 {
18                     instance= new Singlton();
19                 }
20             21             }
return instance; 22 } 23 } 24 }
复制代码

而我们使用静态对象在静态结构方法里为它进行初始化,这种方式也非常在程序中看到,如:

复制代码
 1 public sealed class Singlton
 2 {
 3     static readonly Singlton instance = null;
 4  
 5     static Singlton()
 6     { instance = new Singlton();}
 7  
 8     public static Singlton Instance
 9     {
10         get
11         {
12             return instance;
13         }
14     }
15 }
复制代码

这种方法及其它单件模式有一个问题,就是如果希望去更新单件对象的值,是无法实现的,比如,instance对象希望从数据库中取出一个列表,而列表的信息有可能

发生变化,怎样保证instance里取的是最新的信息呢,这样我们可以在单件中引入时间触发器的概念,代码如下:

复制代码
 1     public class CategoryRepository : Car_RentalRepositoryBase, ICategoryRepository
 2     {
 3         #region 静态树结构,每1分钟去获一下数据库
 4         static List<Category> categoryList = null;
 5         /// <summary>
 6         /// 数据实体
 7         /// </summary>
 8         public static volatile List<Category> Instance = null;
 9         static CategoryRepository categoryRepository = new CategoryRepository();
10         static System.Timers.Timer sysTimer = new System.Timers.Timer(600000);
11         static CategoryRepository()
12         {
13             Reload();//第一次加载
14             sysTimer.AutoReset = true;
15             sysTimer.Enabled = true;
16             sysTimer.Elapsed += new System.Timers.ElapsedEventHandler(sysTimer_Elapsed);
17             sysTimer.Start();
18         }
19 
20         /// <summary>
21         /// 被订阅了Elapsed事件的方法,每隔一段时间去重新获取数据列表
22         /// </summary>
23         /// <param name="sender"></param>
24         /// <param name="e"></param>
25         static void sysTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
26         {
27             Reload();
28         }
29 
30         internal static void Reload()
31         {
32             categoryList = categoryRepository.GetModel().OrderBy(i => i.SortNumber).ToList();
33             Instance = categoryList.Where(i => i.ID != 1).ToList();
34         }
35 }
复制代码

这种方式解决了实例不能获取最新的问题。

最后,奉献出国外牛人写了的泛型单件类,如果实现的类直接继承它即可。

复制代码
 1  /// <summary>
 2     /// 泛型单例基类
 3     /// </summary>
 4     public abstract class Singleton<TEntity> where TEntity : class
 5     {
 6         private static readonly Lazy<TEntity> _instance
 7           = new Lazy<TEntity>(() =>
 8           {
 9               var ctors = typeof(TEntity).GetConstructors(
10                   BindingFlags.Instance
11                   | BindingFlags.NonPublic
12                   | BindingFlags.Public);
13               if (ctors.Count() != 1)
14                   throw new InvalidOperationException(String.Format("Type {0} must have exactly one constructor.", typeof(TEntity)));
15               var ctor = ctors.SingleOrDefault(c => c.GetParameters().Count() == 0 && c.IsPrivate);
16               if (ctor == null)
17                   throw new InvalidOperationException(String.Format("The constructor for {0} must be private and take no parameters.", typeof(TEntity)));
18               return (TEntity)ctor.Invoke(null);
19           });
20 
21         public static TEntity Instance
22         {
23             get { return _instance.Value; }
24         }
25     }