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

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

说说设计模式~单件模式(Singleton)-LMLPHP
 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 }
说说设计模式~单件模式(Singleton)-LMLPHP

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

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

说说设计模式~单件模式(Singleton)-LMLPHP
 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 }
说说设计模式~单件模式(Singleton)-LMLPHP

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

说说设计模式~单件模式(Singleton)-LMLPHP
 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 }
说说设计模式~单件模式(Singleton)-LMLPHP

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

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

说说设计模式~单件模式(Singleton)-LMLPHP
 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 }
说说设计模式~单件模式(Singleton)-LMLPHP

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

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

说说设计模式~单件模式(Singleton)-LMLPHP
 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 }
04-25 02:10