设计模式目录:html
本篇目录:java
单例模式(Singleton)能够说是最简单的模式,对.net来讲,由于不须要考虑到垃圾回收机制,实现起来很简单,可是对于没有提供内存管理的平台来讲,好比C++,由于单例模式只考虑建立对象,因此使用的时候要考虑全面些。函数
其实说到些设计模式,咱们有时候用到的真的不多,就像飞机零部件的模具不适用于汽车制造同样,某些设计模式也只在特定的环境下使用,单例模式的使用场景通常是资源管理器等,像说的最多的就是打印机场景:每台计算机能够有若干个打印机,但只能有一个Printer Spooler,以免两个打印做业同时输出到打印机中。每台计算机能够有若干传真卡,可是只应该有一个软件负责管理传真卡,以免出现两份传真做业同时传到传真卡中的状况。每台计算机能够有若干通讯端口,系统应当集中管理这些通讯端口,以免一个通讯端口同时被两个请求同时调用。说白点就是一个男人能够有不少女友,可是结婚生子的只能是其中一个。一夫多妻的状况就不是单例模式了,那应该是“多态”了。哈哈。post
单例模式(Singleton)在.net中的定义是:一个类有且仅有一个实例,而且自行实例化向整个系统提供。学习
从定义中咱们能够看出,单例模式所具备的三个要点:测试
根据所说的要点,咱们能够在.net中这样简单的实现:url
1 public class SingletonTest 2 { 3 public static SingletonTest model; 4 private SingletonTest() 5 { } 6 public static SingletonTest getSingleton() 7 { 8 if (model==null) 9 { 10 model = new SingletonTest(); 11 } 12 return model; 13 } 14 }
代码就这么简单,在getSingleton()方法返回实例的时候要先判断对象是否已经被实例化,若是是就不须要从新建立了。
上面的代码看起来没什么问题,可是在多线程的状况下就会出现问题,咱们来开几个线程测试下:
1 public class SingletonTest 2 { 3 public static SingletonTest model; 4 private SingletonTest() 5 { } 6 public static SingletonTest getSingleton() 7 { 8 if (model==null) 9 { 10 Console.WriteLine(String.Format("我是被线程:{0}建立的!", Thread.CurrentThread.Name)); 11 model = new SingletonTest(); 12 } 13 return model; 14 } 15 }
1 class Program 2 { 3 static void Main(string[] args) 4 { 5 Program p1 = new Program(); 6 p1.Test(); 7 Console.ReadLine(); 8 } 9 10 private void Test() 11 { 12 Thread newThread; 13 ThreadStart ts = new ThreadStart(DoWork); 14 for (int counter = 1; counter < 6; counter++) 15 { 16 newThread = new Thread(ts); 17 newThread.Name = "蟋蟀" + counter; 18 newThread.Start(); 19 } 20 } 21 22 protected void DoWork() 23 { 24 //调用返回对象方法 25 SingletonTest.getSingleton(); 26 } 27 }
执行结果:
根据上图的执行结果,会发现SingletonTest对象被实例化了2次,按照单例模式(Singleton)的特性:一个类只能有一个实例,那就不是单例模式了,为何会实例化两次呢?由于咱们的计算机执行速度很快,在某一个时间点,线程1在执行完if (model==null)这段代码,还没执行model = new SingletonTest(),线程2恰好执行判断对象是否null,就是说线程1和线程2都会进入下面的if判断体中实例化对象。
关于单例模式的线程安全问题,网上一找一大堆,在《漫谈设计模式》这本书中,做者也提到了线程安全问题,java中是使用的是“Double-Check Locking”方法,还有序列化的问题,这边先不考虑,其实在.net中解决线程安全的问题也很简单,就是用lock锁,咱们根据上面的代码,再来修改下,而后作个测试:
1 public class SingletonTest 2 { 3 private static SingletonTest singleton; 4 private static readonly object syncObject = new object(); 5 /// <summary> 6 /// 构造函数必须是私有的 7 /// 这样在外部便没法使用 new 来建立该类的实例 8 /// </summary> 9 private SingletonTest() 10 { } 11 /// <summary> 12 /// 定义一个全局访问点 13 /// 设置为静态方法 14 /// 则在类的外部便无需实例化就能够调用该方法 15 /// </summary> 16 /// <returns></returns> 17 public static SingletonTest getSingleton() 18 { 19 //这里能够保证只实例化一次 20 //即在第一次调用时实例化 21 //之后调用便不会再实例化 22 //第一重 singleton == null 23 if (singleton == null) 24 { 25 lock (syncObject) 26 { 27 //第二重 singleton == null 28 if (singleton == null) 29 { 30 Console.WriteLine(String.Format("我是被线程:{0}建立的!", Thread.CurrentThread.Name)); 31 singleton = new SingletonTest(); 32 } 33 } 34 } 35 return singleton; 36 } 37 }
执行结果:
从上面的执行结果咱们就能够看到,对象仅被实例化了一次,在某段代码体中,只能有且只有一个线程访问,加锁的目的就比如:咱们去火车站售票大厅买票,由于买票的人太多,为了缓解压力,就多开了几个售票窗口(线程),好比南京到徐州的G110次列车只有一张票,窗口A和窗口B的人同时都在买这一班次的票,这时候就要加锁,否则就有可能会出现只有一张票,可是卖出去两张。话题跑偏了,哈哈。
示例代码下载:Singleton.rar
关于模式,再多说两句,在某些状况下,像上面所说的:模式能够当作现实生活中的模具,有些产品(项目)是由一种模具(模式)生成出来的,好比杯子、瓶子等,有些产品(项目)是由多种模具(模式)生成出来,而后组合而成的,好比汽车、飞机等,是由成千上万个零部件组合造成的。就是说学会模式后要会懂得组合,并且要“合适”的组合,这样才会作出一个完善的产品(项目)。
仍是那就话:骚年们,和小菜一块儿整理学习吧,未完待续。。。