.NET设计模式(2):单件模式(Singleton Pattern)

单件模式(Singleton Pattern

——.NET设计模式系列之二

Terrylee20051207

概述

Singleton模式要求一个类有且仅有一个实例,并且提供了一个全局的访问点。这就提出了一个问题:如何绕过常规的构造器,提供一种机制来保证一个类只有一个实例?客户程序在调用某一个类时,它是不会考虑这个类是否只能有一个实例等问题的,所以,这应该是类设计者的责任,而不是类使用者的责任。

从另一个角度来说,Singleton模式其实也是一种职责型模式。因为我们创建了一个对象,这个对象扮演了独一无二的角色,在这个单独的对象实例中,它集中了它所属类的所有权力,同时它也肩负了行使这种权力的职责!

意图

保证一个类仅有一个实例,并提供一个访问它的全局访问点。

模型图

逻辑模型图:

物理模型图:

生活中的例子

美国总统的职位是Singleton,美国宪法规定了总统的选举,任期以及继任的顺序。这样,在任何时刻只能由一个现任的总统。无论现任总统的身份为何,其头衔"美利坚合众国总统"是访问这个职位的人的一个全局的访问点。

五种实现

1.简单实现

 

 

 1public sealed class Singleton
 2{
 3    static Singleton instance=null;
 4
 5    Singleton()
 6    {
 7    }

 8
 9    public static Singleton Instance
10    {
11        get
12        {
13            if (instance==null)
14            {
15                instance = new Singleton();
16            }

17            return instance;
18        }

19    }

20}

这种方式的实现对于线程来说并不是安全的,因为在多线程的环境下有可能得到Singleton类的多个实例。如果同时有两个线程去判断(instance == null),并且得到的结果为真,这时两个线程都会创建类Singleton的实例,这样就违背了Singleton模式的原则。实际上在上述代码中,有可能在计算出表达式的值之前,对象实例已经被创建,但是内存模型并不能保证对象实例在第二个线程创建之前被发现。

 

该实现方式主要有两个优点:

l         由于实例是在 Instance 属性方法内部创建的,因此类可以使用附加功能(例如,对子类进行实例化),即使它可能引入不想要的依赖性。

l         直到对象要求产生一个实例才执行实例化;这种方法称为“惰性实例化”。惰性实例化避免了在应用程序启动时实例化不必要的 singleton

2.安全的线程

 1public sealed class Singleton
 2{
 3    static Singleton instance=null;
 4    static readonly object padlock = new object();
 5
 6    Singleton()
 7    {
 8    }

 9
10    public static Singleton Instance
11    {
12        get
13        {
14            lock (padlock)
15            {
16                if (instance==null)
17                {
18                    instance = new Singleton();
19                }

20                return instance;
21            }

22        }

23    }

24}

25
26

 

这种方式的实现对于线程来说是安全的。我们首先创建了一个进程辅助对象,线程在进入时先对辅助对象加锁然后再检测对象是否被创建,这样可以确保只有一个实例被创建,因为在同一个时刻加了锁的那部分程序只有一个线程可以进入。这种情况下,对象实例由最先进入的那个线程创建,后来的线程在进入时(instence == null)为假,不会再去创建对象实例了。但是这种实现方式增加了额外的开销,损失了性能。

3.双重锁定

 1public sealed class Singleton
 2{
 3    static Singleton instance=null;
 4    static readonly object padlock = new object();
 5
 6    Singleton()
 7    {
 8    }

 9
10    public static Singleton Instance
11    {
12        get
13        {
14            if (instance==null)
15            {
16                lock (padlock)
17                {
18                    if (instance==null)
19                    {
20                        instance = new Singleton();
21                    }

22                }

23            }

24            return instance;
25        }

26    }

27}

28

这种实现方式对多线程来说是安全的,同时线程不是每次都加锁,只有判断对象实例没有被创建时它才加锁,有了我们上面第一部分的里面的分析,我们知道,加锁后还得再进行对象是否已被创建的判断。它解决了线程并发问题,同时避免在每个 Instance 属性方法的调用中都出现独占锁定。它还允许您将实例化延迟到第一次访问对象时发生。实际上,应用程序很少需要这种类型的实现。大多数情况下我们会用静态初始化。这种方式仍然有很多缺点:无法实现延迟初始化。

4.静态初始化

 1public sealed class Singleton
 2{
 3    static readonly Singleton instance=new Singleton();
 4
 5    static Singleton()
 6    {
 7    }

 8
 9    Singleton()
10    {
11    }

12
13    public static Singleton Instance
14    {
15        get
16        {
17            return instance;
18        }

19    }

20}

21

看到上面这段富有戏剧性的代码,我们可能会产生怀疑,这还是Singleton模式吗?在此实现中,将在第一次引用类的任何成员时创建实例。公共语言运行库负责处理变量初始化。该类标记为 sealed 以阻止发生派生,而派生可能会增加实例。此外,变量标记为 readonly,这意味着只能在静态初始化期间(此处显示的示例)或在类构造函数中分配变量。

该实现与前面的示例类似,不同之处在于它依赖公共语言运行库来初始化变量。它仍然可以用来解决 Singleton 模式试图解决的两个基本问题:全局访问和实例化控制。公共静态属性为访问实例提供了一个全局访问点。此外,由于构造函数是私有的,因此不能在类本身以外实例化 Singleton 类;因此,变量引用的是可以在系统中存在的唯一的实例。

由于 Singleton 实例被私有静态成员变量引用,因此在类首次被对 Instance 属性的调用所引用之前,不会发生实例化。

这种方法唯一的潜在缺点是,您对实例化机制的控制权较少。在 Design Patterns 形式中,您能够在实例化之前使用非默认的构造函数或执行其他任务。由于在此解决方案中由 .NET Framework 负责执行初始化,因此您没有这些选项。在大多数情况下,静态初始化是在 .NET 中实现 Singleton 的首选方法。

5.延迟初始化

 1public sealed class Singleton
 2{
 3    Singleton()
 4    {
 5    }

 6
 7    public static Singleton Instance
 8    {
 9        get
10        {
11            return Nested.instance;
12        }

13    }

14    
15    class Nested
16    {
17        static Nested()
18        {
19        }

20
21        internal static readonly Singleton instance = new Singleton();
22    }

23}

24

这里,初始化工作有Nested类的一个静态成员来完成,这样就实现了延迟初始化,并具有很多的优势,是值得推荐的一种实

现方式。

实现要点

l        Singleton模式是限制而不是改进类的创建。

l         Singleton类中的实例构造器可以设置为Protected以允许子类派生。

l         Singleton模式一般不要支持Icloneable接口,因为这可能导致多个对象实例,与Singleton模式的初衷违背。

l         Singleton模式一般不要支持序列化,这也有可能导致多个对象实例,这也与Singleton模式的初衷违背。

l         Singleton只考虑了对象创建的管理,没有考虑到销毁的管理,就支持垃圾回收的平台和对象的开销来讲,我们一般没必要对其销毁进行特殊的管理。

l         理解和扩展Singleton模式的核心是“如何控制用户使用new对一个类的构造器的任意调用”。

 

 

l         可以很简单的修改一个Singleton,使它有少数几个实例,这样做是允许的而且是有意义的

优点

l         实例控制:Singleton 会阻止其他对象实例化其自己的 Singleton 对象的副本,从而确保所有对象都访问唯一实例

l         灵活性:因为类控制了实例化过程,所以类可以更加灵活修改实例化过程

缺点

l         开销:虽然数量很少,但如果每次对象请求引用时都要检查是否存在类的实例,将仍然需要一些开销。可以通过使用静态初始化解决此问题,上面的五种实现方式中已经说过了。

l          可能的开发混淆:使用 singleton 对象(尤其在类库中定义的对象)时,开发人员必须记住自己不能使用 new 关键字实例化对象。因为可能无法访问库源代码,因此应用程序开发人员可能会意外发现自己无法直接实例化此类。

l         对象的生存期:Singleton 不能解决删除单个对象的问题。在提供内存管理的语言中(例如基于 .NET Framework 的语言),只有 Singleton 类能够导致实例被取消分配,因为它包含对该实例的私有引用。在某些语言中(如 C++),其他类可以删除
对象实例,但这样会导致 Singleton 类中出现悬浮引用。

适用性

l         当类只能有一个实例而且客户可以从一个众所周知的访问点访问它时。

l         当这个唯一实例应该是通过子类化可扩展的,并且客户应该无需更改代码就能使用一个扩展的实例时。

应用场景

l         每台计算机可以有若干个打印机,但只能有一个Printer Spooler,避免两个打印作业同时输出到打印机。
(摘自吕震宇的
C#设计模式(7)-Singleton Pattern

l         PC机中可能有几个串口,但只能有一个COM1口的实例。

l         系统中只能有一个窗口管理器。

l         .NET Remoting中服务器激活对象中的Sigleton对象,确保所有的客户程序的请求都只有一个实例来处理。

完整示例

这是一个简单的计数器例子,四个线程同时进行计数。

 1using System;
 2using System.Threading;
 3
 4namespace SigletonPattern.SigletonCounter
 5{
 6    /// <summary>
 7    /// 功能:简单计数器的单件模式
 8    /// 编写:Terrylee
 9    /// 日期:2005年12月06日
10    /// </summary>

11    public class CountSigleton
12    {
13        ///存储唯一的实例
14        static CountSigleton uniCounter = new CountSigleton();  
15   
16        ///存储计数值
17        private int totNum = 0;  
18   
19        private CountSigleton() 
20   
21        
22            ///线程延迟2000毫秒
23            Thread.Sleep(2000);
24        }
 
25   
26        static public CountSigleton Instance() 
27   
28        
29   
30            return uniCounter; 
31   
32        }
 
33        
34        ///计数加1
35        public void Add()
36        
37            totNum ++;
38        }
  
39        
40        ///获得当前计数值
41        public int GetCounter()
42        
43            return totNum;
44        }
 
45
46    }

47}

48

 

 1using System;
 2using System.Threading;
 3using System.Text;
 4
 5namespace SigletonPattern.SigletonCounter
 6{
 7    /// <summary>
 8    /// 功能:创建一个多线程计数的类
 9    /// 编写:Terrylee
10    /// 日期:2005年12月06日
11    /// </summary>

12    public class CountMutilThread
13    {
14        public CountMutilThread()
15        {
16            
17        }

18
19        /// <summary>
20        /// 线程工作
21        /// </summary>

22        public static void DoSomeWork()
23        {
24            ///构造显示字符串
25            string results = "";
26
27            ///创建一个Sigleton实例
28            CountSigleton MyCounter = CountSigleton.Instance();
29
30            ///循环调用四次
31            for(int i=1;i<5;i++)
32            {
33                ///开始计数
34                MyCounter.Add();
35                
36                results +="线程";
37                results += Thread.CurrentThread.Name.ToString() + "——〉";
38                results += "当前的计数:";
39                results += MyCounter.GetCounter().ToString();
40                results += "\n";
41
42                Console.WriteLine(results);
43                
44                ///清空显示字符串
45                results = "";
46            }

47        }

48
49        public void StartMain()
50        {
51
52            Thread thread0 = Thread.CurrentThread; 
53   
54            thread0.Name = "Thread 0"
55   
56            Thread thread1 =new Thread(new ThreadStart(DoSomeWork)); 
57   
58            thread1.Name = "Thread 1"
59   
60            Thread thread2 =new Thread(new ThreadStart(DoSomeWork)); 
61   
62            thread2.Name = "Thread 2"
63   
64            Thread thread3 =new Thread(new ThreadStart(DoSomeWork)); 
65   
66            thread3.Name = "Thread 3"
67   
68            thread1.Start(); 
69   
70            thread2.Start(); 
71   
72            thread3.Start(); 
73            
74            ///线程0也只执行和其他线程相同的工作
75            DoSomeWork(); 
76        }

77    }

78}

79

 

 1using System;
 2using System.Text;
 3using System.Threading;
 4
 5namespace SigletonPattern.SigletonCounter
 6{
 7    /// <summary>
 8    /// 功能:实现多线程计数器的客户端
 9    /// 编写:Terrylee
10    /// 日期:2005年12月06日
11    /// </summary>

12    public class CountClient
13    {
14        public static void Main(string[] args)
15        {
16       CountMutilThread cmt = new CountMutilThread();
17
18            cmt.StartMain();
19
20            Console.ReadLine();
21        }

22    }

23}

24

 

 

总结

Singleton设计模式是一个非常有用的机制,可用于在面向对象的应用程序中提供单个访问点。文中通过五种实现方式的比较和一个完整的示例,完成了对Singleton模式的一个总结和探索。用一句广告词来概括Singleton模式就是“简约而不简单”。

_________________________________________________________________________________________________
源码下载:/Files/Terrylee/SigletonPattern.rar

参考文献:

C#计模式》,中国电力出版社

使用 Microsoft .NET 的企业解决方案模式

Implementing the Singleton Pattern in C#

MSDNExploring the Singleton Design Pattern

吕震宇C#设计模式(7)-Singleton Pattern

C#的Singleton设计模式

作者:TerryLee
出处:http://terrylee.cnblogs.com
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
posted @ 2005-12-09 09:31 TerryLee 阅读(69524) 评论(152)  编辑 收藏 网摘 所属分类: [05]  架构与设计

评论共2页: 上一页 1 2 
  回复  引用    
#101楼2006-12-22 15:32 | hnsdxujunyi[未注册用户]
同样受教菲浅,继续支持,并且坚持学习。
熟读多遍,思考再三,重视发言,只问困惑。

  回复  引用  查看    
#102楼[楼主]2006-12-23 16:21 | TerryLee      
@蓝星
:)

  回复  引用  查看    
#103楼[楼主]2006-12-23 16:22 | TerryLee      
@hnsdxujunyi
:)

  回复  引用  查看    
#104楼2006-12-27 11:35 | Charly      
8错,最近开始学习设计模式。。。
  回复  引用    
#105楼2006-12-27 12:54 | 边城浪[未注册用户]
用.NET2.0中静态类来替换Singleton模式是不是更好一些呢?
  回复  引用    
#106楼2007-01-10 21:41 | yanzimywife[未注册用户]
写的不错,支持
  回复  引用    
#107楼2007-01-11 16:46 | qcrsoft[未注册用户]
在程序中引用了WEB Services,我想这个web services只有一个实例,单件模式能不能派上用场呢?我一时想不明白,高手们给点拨一下,感激!
  回复  引用  查看    
#108楼2007-01-12 20:56 | MingG      
刚学习设计模式,看了一头雾水,
terrylee大哥的文章 爽~~`
以后有不懂的地方就来这逛喽...

  回复  引用  查看    
#109楼[楼主]2007-01-15 08:38 | TerryLee      
@MingG
欢迎常来:)

  回复  引用    
#110楼2007-02-06 17:02 | [匿名] [未注册用户]
学习,支持
  回复  引用    
#111楼2007-02-26 20:28 | sapphire[未注册用户]
在“5.延迟初始化”中:
public sealed class Singleton
{
Singleton()
{
}
......
是不是要写为:
public sealed class Singleton
{
internal Singleton()
{
}
......
不然在Nested类中无法 new Singleton()

  回复  引用  查看    
#112楼2007-03-22 21:37 | 李大力      
受益匪浅
  回复  引用    
#113楼2007-04-06 15:25 | cqy[未注册用户]
数据库访问类,有必要使用单件模式么?
  回复  引用    
#114楼2007-04-13 13:24 | wenchenxi@163.com[未注册用户]
///开始计数
MyCounter.Add();

results += "线程";
results += Thread.CurrentThread.Name.ToString() + "——〉";
results += "当前的计数:";
results += MyCounter.GetCounter().ToString();
//results += "\n";

Console.WriteLine(results);
}
///清空显示字符串
results = "";


我测试了,上面的代码没有线程安全性,即输出结果可能不能够控制就是本次增加后的结果。
所以应该把这段代码锁定。lock(o)

  回复  引用    
#115楼2007-04-13 16:29 | jxdworld[未注册用户]
谢谢,很详细,也很清楚!
  回复  引用    
#116楼2007-05-10 17:32 | 担当[未注册用户]
不错,受益匪浅
  回复  引用  查看    
#117楼2007-05-13 20:31 | 逍遥剑客      
是不是有必要在 DoSomeWork()的for 循环中lock(MyCounter)??
要不然在在该多线程的例子中不安全!

  回复  引用    
#118楼2007-06-06 09:32 | 贾宝玉[未注册用户]
真牛!
  回复  引用    
#119楼2007-06-20 16:58 | xiekeli[未注册用户]
一起研究OO,多赐教:借宝地宣传一下自己的blog,真诚期待各位的指点:http://xiekeli.blogbus.com/index.html
  回复  引用  查看    
#120楼2007-06-26 20:14 | JBoy      
学习ing! 受益了


  回复  引用  查看    
#121楼2007-06-26 20:54 | JBoy      
有个问题,请教一下老大:在双重锁定实现的代码中,
if (instance==null)
{
lock (padlock)
{
if (instance==null) //这个决断有没有必要?
{
instance = new Singleton();
}
}
}

有没有必须在锁定后再来判断instance == null呢?
既然已经锁定了,只能有一个线程来访问,就没有必要再决断对象是否为空了。我是菜鸟,不怎么懂的。

  回复  引用  查看    
#122楼2007-06-26 20:58 | JBoy      
还有一个问题:为什么在应用程序中很少用双重锁定现实单例模式?
  回复  引用  查看    
#123楼2007-06-26 21:16 | JBoy      
再一个问题(我的问题是不是太多了?):第五种模式实现,在多线程的情况下是不安全的,是吗?
  回复  引用    
#124楼2007-06-30 14:05 | protorock[未注册用户]
楼主给的例子有问题。运行后的结果出现:

线程Thread 1-->当前计数值:2
……
线程Thread 2-->当前计数值:2

例子程序实现了singleton模式,但是没有解决同步问题!原因很简单,你考虑考虑吧 :-)

  回复  引用    
#125楼2007-06-30 14:08 | protorock[未注册用户]
我的计算机是“至强”双核CPU
  回复  引用    
#126楼2007-07-08 03:37 | yanzimywife[未注册用户]
当这个唯一实例应该是通过子类化可扩展的,并且客户应该无需更改代码就能使用一个扩展的实例时。
这句话没有看懂啊!

  回复  引用    
#127楼2007-08-07 18:32 | 监控局域网[未注册用户]
不错。写程序不学设计模式是写不出好程序的。多谢楼主。
  回复  引用    
#128楼2007-08-23 15:33 | 华为菜鸟[未注册用户]
看了N次了,每次的感觉都不一样!
支持!!支持!!感谢楼主的无私!
同时我更佩服楼主的人品。做人做到这样,真的是很成功!
学习了!!

  回复  引用  查看    
#129楼2007-09-17 20:30 | XuQ      
感觉双重锁那里的第二次instance == null 判断没有必要,terrylee为什么要加上呢,不解,请指教
  回复  引用  查看    
#130楼2007-09-25 10:48 | 高原之上      
谢谢
  回复  引用    
#131楼2007-10-31 11:55 | deepfreesea[未注册用户]
@XuQ

A处 if (instance == null)
{
B处
lock (syncRoot)
{
C处 if (instance == null)
instance = new DoubLockSigleton();
}
}

对象为空时,假设有两个线程①②,当①在A处判断返回true,进入B处,此时,②也在A处判断返回true,进入B处,①线程锁定,并创建对象实例,解锁,然后②锁定程序,到达C处,如果C处不判断,则有创建了一个对象实例,形成多个实例

  回复  引用  查看    
#132楼2007-10-31 12:22 | XuQ      
@deepfreesea
呵呵,忽然开朗,看来得看看线程并发类的文章了

  回复  引用  查看    
#133楼2007-11-06 16:33 | 专研.NET      
这东东对我有点难哈,学习中~~~
支持楼主!

  回复  引用  查看    
#134楼2007-11-07 20:17 | scotoma      
在博客园逛了一年的了...现在才理解这些!嗨..好好的努力
  回复  引用  查看    
#135楼2007-12-17 11:32 | Sam Lin      
@protorock
我也出现这个情况:
线程Thread 1-->当前计数值:2
……
线程Thread 2-->当前计数值:2
不知如何解决呢?是什么原因造成的呢?谢谢

  回复  引用  查看    
#136楼2008-02-17 20:00 | ♂风车车.Net      
好文章,谢谢大哥!
报告!我在转载您的文章,我的转载后的地址是:http://www.cnblogs.com/xray2005/archive/2008/02/17/1071492.html" target="_new">http://www.cnblogs.com/xray2005/archive/2008/02/17/1071492.html

  回复  引用  查看    
#137楼[楼主]2008-02-21 19:19 | TerryLee      
@♂风车车.Net
随便转载,呵呵,只要保留原文出处就行了:)

  回复  引用  查看    
#138楼2008-04-15 11:26 | 阿瑞--16hi      
楼主文笔流畅,解说透彻明了,不支持都不行~~~
  回复  引用    
#139楼2008-05-08 19:18 | 周密[未注册用户]
不错啊
^_^

  回复  引用  查看    
#140楼2008-05-11 15:11 | wayich      
学习中。。。。
  回复  引用  查看    
#141楼2008-06-20 17:01 | 杲頔      
您好:我有一个小问题希望得到您的解答:

using System;
using System.Collections.Generic;
using System.Text;

namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
CC1.GetC().A();

CC2.GetC().A();
Console.Read();
}
}


public class CC1
{
private CC2 c2 = CC2.GetC();

private static CC1 c1=new CC1();
public static CC1 GetC()
{
return c1;
}

public void A()
{
c2.Write();
}
public void Write()
{
Console.WriteLine("CC1的Write()");
}
}
public class CC2
{
private CC1 c1 = CC1.GetC();

private static CC2 c2 = new CC2();
public static CC2 GetC()
{
return c2;
}
public void Write()
{
Console.WriteLine("CC2的Write()");
}
public void A()
{
c1.Write();
}
}
}


在这里运行到
public void A()
{
c1.Write();
}
的时候就会提示c1未将对象引用设置到对象的实例。

不知道为什么,希望您给帮我看看,谢谢。

  回复  引用  查看    
#142楼2008-07-04 11:33 | 天生舞男      
你这里计数的时候一定是要加锁的,不然多线程技术会乱

public class CountMultipleTread
{
static readonly object padlock = new object();

public CountMultipleTread()
{
}

/// <summary>
/// 线程工作
/// </summary>
public static void DoSomeWork()
{
string results = "";
CountSingleton myCounter = CountSingleton.Instance();

// 循环调用四次
for (int i = 1; i < 5; i++)
{
lock (padlock)
{
myCounter.Add();
results += "线程";
results += Thread.CurrentThread.Name.ToString() + "-->";
results += "当前的计数:";
results += myCounter.GetCounter().ToString();
results += "\n";

Console.WriteLine(results);

// 清空显示字符串
results = "";
}
}
}

public void StartMain()
{
Thread thread0 = Thread.CurrentThread;

thread0.Name = "Thread 0";

Thread thread1 =new Thread(new ThreadStart(DoSomeWork));

thread1.Name = "Thread 1";

Thread thread2 =new Thread(new ThreadStart(DoSomeWork));

thread2.Name = "Thread 2";

Thread thread3 =new Thread(new ThreadStart(DoSomeWork));

thread3.Name = "Thread 3";

thread1.Start();

thread2.Start();

thread3.Start();

/**////线程0也只执行和其他线程相同的工作
DoSomeWork();

}

}

  回复  引用  查看    
#143楼2008-07-14 10:39 | 雅阁布      
UP!!!!
  回复  引用  查看    
#144楼2008-07-16 09:49 | Ivan-Yan      
@TerryLee
ajax的学习就是从你这里获得的,很受用,谢谢~
现在开始学习设计模式,还准备从这里开始,请多多指教~~
---
有一种情况,我不知道算不算符合Singleton pattern:
winfrom 中,利用menuStrip1实现菜单,每个菜单选项每次只能打开一个form。
--
我用一个静态变量进行控制
frmmain:
private void subMenu1ToolStripMenuItem_Click(object sender, EventArgs e)
{
if (frm.sign == false)
{
frm f = new frm();
f.MdiParent = this;
frm.sign = true;
f.Show();

}
else
{
MessageBox.Show("该窗体已经存在~");
return;
}

}
---
frm:
public partial class frm : Form
{
public static bool sign = false;

public frm()
{
InitializeComponent();
}

private void frm_FormClosing(object sender, FormClosingEventArgs e)
{
sign = false;
}
}
=================
请指教~~

  回复  引用  查看    
#145楼[楼主]2008-07-21 10:27 | TerryLee      
@Ivan-Yan
其实文章中都已经介绍了那几种方法,是不是单件模式不重要,只要这种做法能满足你的要求就行。

  回复  引用  查看    
#146楼2008-07-22 18:47 | 鬼不灵      
不知道为什么,我给老大发过邮件和留言,都不给我回呢?
  回复  引用  查看    
#147楼[楼主]2008-07-22 23:44 | TerryLee      
@鬼不灵
不知道你发的是哪个邮箱?我这儿没有收到你的邮件啊?

  回复  引用  查看    
#148楼2008-07-23 11:57 | 鬼不灵      
163的吧,呵呵,我想问下Silverlight能否实现在线的语音聊天功能?提供这方面的类库吗?
还有老大的个人主页的程序不错,我也有域名,可是没有博客程序啊,能否共享下你的个人主页的程序??

  回复  引用  查看    
#149楼[楼主]2008-07-23 22:17 | TerryLee      
@鬼不灵
Silverlight中语音方面的支持我不太清楚

个人主页程序我用的是BlogEngine.NET程序,这里是它的主页,你可以自行下载http://www.dotnetblogengine.net/" target="_new">http://www.dotnetblogengine.net/

  回复  引用  查看    
#150楼2008-07-25 10:10 | 数棋      
弱弱问下,文章图片是怎么做出来的,用什么工具
  回复  引用  查看    
#151楼[楼主]2008-07-27 21:27 | TerryLee      
@数棋
用Visio画的

  回复  引用  查看    
#152楼2008-08-04 15:15 | 晓风残月      
--引用--------------------------------------------------
空空无量:
<br># re: 探索设计模式(二):单件模式(Singleton Pattern) 回复
<br>2006-02-23 23:55 by windwolf
<br>对文中最后一种实现————延迟初始化————的机制不是很理解,能解释下吗?
<br>
<br>
<br>我也有此疑问,延迟初始化的好处在什么地方?谢谢
--------------------------------------------------------

这主要与.NET静态构造函数/静态字段初始化时期有关:静态构造函数(静态字段声明并初始化会被编译器包含进静态构造函数)会在第一次访问这个类的成员(静态或者实例,属性或者方法或者字段等等)被CLR调用。

因此,方法4,只要访问Singleton的任意成员(这里应该是静态成员才有意义,实例成员依然需要先访问Instance属性)就会导致语句:static readonly Singleton instance=new Singleton(); 执行,而此时你并没有访问 Singleton.Instance 属性。
而方法5将这一过程延迟到了内嵌类。

方法5看起来会稍微perfect点,特别是当你的 Singletn 属于重量级的,初始化比较耗时,而且每次程序运行不一定都要访问它。

  回复  引用  查看    
#153楼2008-08-10 13:43 | 阿鹏      
:) 晚了您好几年.这么好的东东..
  回复  引用  查看    
#154楼[楼主]2008-08-13 21:44 | TerryLee      
@阿鹏
客气了。。。

  回复  引用  查看    
#155楼2008-08-15 11:37 | Anna Yang      
看此文章觉得比看书更受益,收获更大,谢了!!!
  回复  引用  查看    
#156楼2008-08-15 14:37 | 小手冰冰凉      
不错哦。。。。。。。。比学那些控件有意思的多。。。。比较强大。。
  回复  引用  查看    
#157楼[楼主]2008-08-20 10:34 | TerryLee      
@Anna Yang
:)

  回复  引用  查看    
#158楼[楼主]2008-08-20 10:34 | TerryLee      
@小手冰冰凉
:)

  回复  引用    
#159楼2008-08-25 20:42 | xmol[未注册用户]
public sealed class Singleton
2{
3 static readonly Singleton instance=new Singleton();
4
5 static Singleton()
6 {
7 }
8
9 Singleton()
10 {
11 }
12
13 public static Singleton Instance
14 {
15 get
16 {
17 return instance;
18 }
19 }
20}

public sealed class Singleton
2{
3 static readonly Singleton instance=new Singleton();
4

8
9 Singleton()
10 {
11 }
12
13 public static Singleton Instance
14 {
15 get
16 {
17 return instance;
18 }
19 }
20}有区别吗?后边的没有写静态构造函数

  回复  引用  查看    
#160楼2008-09-19 14:42 | 永恒de影シ      
@TerryLee
挺好的文章啊,看起来有点吃力。主要是不知道怎么去用。

  回复  引用    
#161楼2008-09-22 11:50 | 狗屎[未注册用户]
彩。。。。不错。
  回复  引用    
#162楼2008-09-28 08:59 | pangxiaoliang1982[未注册用户]
http://www.cnblogs.com/melode11/archive/2008/09/28/1301114.html
据说双重锁定有问题,老大可以去看看

  回复  引用  查看    
#163楼2008-10-14 14:02 | dream one minute      
写的很好,好懂。
  回复  引用  查看    
#164楼2008-10-17 15:40 | LZD      
设计模式很好的学习资料!
正在学习中......谢谢

  回复  引用  查看    
#165楼2008-11-06 23:50 | DylanWind      
生活中的例子
强,这么贴近现实
不是这两天改的吧 :)

  回复  引用  查看    
#166楼[楼主]2008-11-07 00:00 | TerryLee      
@DylanWind
貌似这个贴子有好长时间没有修改了:)
------------------------------------
该文被作者在 2008-02-26 18:55 编辑过

  回复  引用  查看    
#167楼2008-11-08 20:12 | 薛锦辉      
public class CountSigleton
应该改为 public sealed class CountSigleton把

  回复  引用  查看    
#168楼[楼主]2008-11-09 12:12 | TerryLee      
@薛锦辉
这一点好像没什么影响……

  回复  引用  查看    
#169楼2008-11-10 00:50 | DylanWind      
--引用--------------------------------------------------
晓风残月: --引用--------------------------------------------------
空空无量:
&lt;br&gt;# re: 探索设计模式(二):单件模式(Singleton Pattern) 回复
&lt;br&gt;2006-02-23 23:55 by windwolf
&lt;br&gt;对文中最后一种实现————延迟初始化————的机制不是很理解,能解释下吗?
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;我也有此疑问,延迟初始化的好处在什么地方?谢谢
--------------------------------------------------------

这主要与.NET静态构造函数/静态字段初始化时期有关:静态构造函数(静态字段声明并初始化会被编译器包含进静态构造函数)会在第一次访问这个类的成员(静态或者实例,属性或者方法或者字段等等)被CLR调用。

因此,方法4,只要访问Singleton的任意成员(这里应该是静态成员才有意义,实例成员依然需要先访问Instance属性)就会导致语句:static readonly Singleton instance=new Singleton(); 执行,而此时你并没有访问 Singleton.Instance 属性。
而方法5将这一过程延迟到了内嵌类。

方法5看起来会稍微perfect点,特别是当你的 Singletn 属于重量级的,初始化比较耗时,而且每次程序运行不一定都要访问它。

--------------------------------------------------------
就是说内联初始化并不能真正的实现Lazy-Initialization?
class Singleton
{
public static readonly Singleton _instance = new Singleton(); //内联初始化
private Singleton(){}
}

  回复  引用  查看    
#170楼2008-11-13 10:05 | prolove2      
写得很好, 很全,很实用。 受教了!
  回复  引用  查看    
#171楼[楼主]2008-11-15 00:30 | TerryLee      
@prolove2
:)

  回复  引用    
#172楼2008-11-17 10:34 | 你的追随者[未注册用户]
楼主你好,感觉你讲的设计模式这一系列文章写的很清晰易懂,能不能整理成pdf文件并提供下载啊,呵呵,供大家学习参考,先谢谢了哦
  回复  引用  查看    
#173楼[楼主]2008-11-17 23:14 | TerryLee      
@你的追随者
整理这么多是需要时间的,呵呵,如果有人乐意整理那再好不过了:)

  回复  引用  查看    
#174楼2008-11-19 12:08 | zhongdaiqi      
这可是跨年度的文章哈~

  回复  引用  查看    
#175楼2008-11-20 11:18 | masterfy      
把需要用到的方法、变量设成静态,直接通过类调用静态方法或静态变量,也可以达到使用单件模式同样的效果吧。
  回复  引用  查看    
#176楼[楼主]2008-11-20 12:36 | TerryLee      
@masterfy
不一样,不同的性质,呵呵

  回复  引用  查看    
#177楼2008-11-20 15:00 | masterfy      
@TerryLee
不太理解。难道用单件模式仅仅是因为在一个线程中创建类的唯一实例吗?创建唯一实例的目的是什么?如果所有的方法、变量都是静态,这样就不需要创建类的实例了,是不是也能达到使用单件模式的目的。

  回复  引用  查看    
#178楼[楼主]2008-11-20 23:53 | TerryLee      
@masterfy
单件模式的目的是什么?保证一个类只有一个实例,既然你所有的东西都是用静态的了,还跟单件有什么关系呢。并不是任何东西都用静态方法就可以解决的。

  回复  引用  查看    
#179楼2009-01-16 02:17 | ChenChuan      
1public sealed class Singleton
2{
3 static Singleton instance=null;
4 static readonly object padlock = new object();
5
6 Singleton()
7 {
8 }
9
10 public static Singleton Instance
11 {
12 get
13 {
14 lock (padlock)
15 {
16 if (instance==null)
17 {
18 instance = new Singleton();
19 }
20 return instance;
21 }
22 }
23 }
24}
25
26


这种方式的实现对于线程来说是安全的。我们首先创建了一个进程辅助对象,线程在进入时先对辅助对象加锁然后再检测对象是否被创建,这样可以确保只有一个实例被创建,因为在同一个时刻加了锁的那部分程序只有一个线程可以进入。这种情况下,对象实例由最先进入的那个线程创建,后来的线程在进入时(instence == null)为假,不会再去创建对象实例了。但是这种实现方式增加了额外的开销,损失了性能。
------------------------------------------------------------------

这里有个问题,我们老师说静态方法本身就是线程安全的了,为何还要在静态方法里加锁来防止线程安全呢,能给我说说吗,我是个初学者

  回复  引用  查看    
#180楼2009-02-05 10:11 | yhb199      
不错,还是那句话,简约不简单,你也是
报告,转载啦,地址:http://yhb199.cnblogs.com/" target="_new">http://yhb199.cnblogs.com/

  回复  引用  查看    
#181楼2009-03-24 17:04 | 驢騎士      
楼主厉害
能写全就更好了

  回复  引用  查看    
#182楼2009-03-27 14:52 | sinxsoft      
为什么不用静态构造函数?

public sealed class Singleton
{
public static readonly Singleton single = null;
static Singleton()
{
single = new Singleton(DateTime.Now);
}

DateTime _date;
public DateTime Date
{
get { return _date; }
}

private Singleton(DateTime date)
{
_date = date;
}
}


static void Main(string[] args)
{

Console.Write(Singleton.single.Date.ToString());
Console.ReadLine();
}

  回复  引用  查看    
#183楼2009-03-27 14:53 | sinxsoft      
哦,当然,构造函数必须私有:
private Singleton(DateTime date)
{
_date = date;
}

  回复  引用  查看    
#184楼2009-04-03 15:36 | 小伦      
学习ing......
  回复  引用    
#185楼2009-04-08 15:13 | 雁过留影
尽管刚刚接触,看上去有点费劲,不过,感觉很好。
建议写完,我会认真的看完的。
精神上严重支持你!

  回复  引用  查看    
#186楼2009-04-14 11:12 | AllenLee      
各位前辈走得好快噢
小弟刚刚开始学设计模式,落下好多
本人强烈支持楼主,希望在这里有个好的开始。

  回复  引用  查看    
#187楼2009-04-20 15:58 | 龙潜冰风悄林      
楼主,请教下关于你举的那个例子:
1、运行你的那个例子:结果是按线程3-2-0-1的循序执行
2、在1的基础上注释掉Thread.Sleep(2000); 结果是按线程1-2-0-3的循序执行
3、在1的基础上,将DoSomeWork(); 移动到thread0.Name="Thread0"之后,执行顺序是0-1-2-3

能说明是什么原因

  回复  引用  查看    
#188楼2009-04-29 17:24 | SoSo_Ak      
学习学习~~~
  回复  引用    
#189楼2009-05-06 16:30 | 龙骑士
写的很好..谢谢楼主分享..呵呵..
  回复  引用  查看    
#190楼2009-05-07 12:00 | 月阳      
不错,值 得学习。
  回复  引用  查看    
#191楼2009-05-07 18:21 | Lancker      
这里,初始化工作有Nested类的一个静态成员来完成,这样就实现了延迟初始化,并具有很多的优势,是值得推荐的一种实


这个Nested好像是打错了~

  回复  引用  查看    
#192楼2009-06-06 09:57 | Jacky.Zhou      
设计模式应该是对于编程人员是非常重要的1
  回复  引用  查看    
#193楼2009-06-17 19:51 | mrxliu      
好全!SO good,连在什么地方用也大体说了下!
  回复  引用  查看    
#194楼2009-06-17 20:01 | mrxliu      
最近在写自定义控件,自己无意之间用到了你上面说的第一个方法,后来又随意的看了下 《设计模式》 也正好看到 “单件模式” , 哇塞,原来都是一个原理,难道很多事情都是无意之间产生有意,接着灵感触发又能学到N多新东西。也拜读了大牛的文章,牛B!
评论共2页: 上一页 1 2 



发表评论

昵称: [登录] [注册]

主页:

邮箱:(仅博主可见)

评论内容:

  登录  注册

[使用Ctrl+Enter键快速提交评论]

0 293509




相关文章:

相关链接: