做这么久的项目,却没有总结的习惯。再这样下去,注定成不了好的程序员
什么是单例 :
Ensure a class only has one instance,and provide a global point of access to。它的主要特点不是根据客户程序调用生成一个新的实例,而是控制某个类型的实例数量-唯一一个。(《设计模式-基于C#的工程化实现及扩展》,王翔)。也就是说,单例模式就是保证在整个应用程序的生命周期中,在任何时刻,被指定的类只有一个实例,并为客户程序提供一个获取该实例的全局访问点。
特点:
1,一个类只能有一个实例;
2,自己创建这个实例;
3,整个系统都要使用这个实例。
苹果官方单例代码:具体点击链接
#import
'''
/* Singleton.h */
#import <Foundation/Foundation.h>
@interfaceSingleton:NSObject
+(Singleton*)instance;
@end
/* Singleton.m */
#import "Singleton.h"
staticSingleton*instance=nil;
@implementationSingleton
+(Singleton*)instance
{
if(!instance)
{
instance=[[superallocWithZone:NULL]init];
}
returnin stance;
}
+(id)allocWithZone:(NSZone*)zone
{
return [self instance];
}
-(id)copyWithZone:(NSZone*)zone
{
return self;
}
-(id)init{
if(instance)
{
return instance;
}
self=[super init];
return self;
}
-(id)retain{
return self;
}
-(oneway void)release
{
// Do nothing
}
-(id)autorelease{
return self;
}
-(NSUInteger)retainCount
{
return NSUIntegerMax;
}
@end
为什么用单例:
单例的意图是为了保证一个类只有一个实例,并提供访问它的唯一全局访问点。之前一直在想,如果要完成这样的功能,其实全局变量也可以做到,不是吗?只要一个全局变量,然后在各个需要的地方调用这个全局变量即可,必要的时候可以extern,一样也可以完成这样的功能。那么,为什么不直接使用全局变量,而要搞一个单例出来?单例到底比全局变量好在哪儿?首先,全局变量不能保证全局只有一个类的实例,你完全可以声明同一个类的多个实例。当然,如果你注意一点,那么用全局方法保证全局只有一个该类的实例还是可以做到的,但你得很注意,让自己不要在其他地方声明多一个实例。而单例却可以轻松的做到这一点,并能保证全局只有一个该类的实例可被访问。其次,相对来说,使用单例时,代码会显得优雅一些。
单例模式与全局变量的详细比较
单例模式的其他应用场景
什么时候用单例
单例的使用主要是在需要保证全局只有一个实例可以被访问的情况,比如[系统]日志的输出、[操作系统]的任务管理器等。
一些细节
通常,我们看到的单例类没有析构函数,那么new出来的[空间]是怎么释放的呢?一般有2种做法,一种是不做任何操作,等最后程序结束时操作系统回收[资源];另外一种是另外搞一个函数或者类,来处理delete操作。对于像我这样的初级使用学者,还是选择第一种更方便,第二种相对来说需要考虑更多一些。
两种经典的多线程单例写法
一、经典模式:
publicclass Singleton
{
privatestatic Singleton instance;
private Singleton()
{}
publicstatic Singleton GetInstance()
{
if(instance==null)
{
instance=new Singleton();
}
return instance;
}
解析如下:
1)首先,该Singleton的构造函数必须是私有的,以保证客户程序不会通过new()操作产生一个实例,达到实现单例的目的;
2)因为静态变量的生命周期跟整个应用程序的生命周期是一样的,所以可以定义一个私有的静态全局变量instance来保存该类的唯一实例;
3)必须提供一个全局函数访问获得该实例,并且在该函数提供控制实例数量的功能,即通过if语句判断instance是否已被实例化,如果没有则可以同new()创建一个实例;否则,直接向客户返回一个实例。
在这种经典模式下,没有考虑线程并发获取实例问题,即可能出现两个线程同时获取instance实例,且此时其为null时,就会出现两个线程分别创建了instance,违反了单例规则。因此,需对上面代码修改。
二、多线程下的单例模式
1、Lazy模式
publicclass Singleton
{
privatestatic Singleton instance;
private Singleton()
{
}
publicstatic Singleton GetInstance()
{
if(instance==null)
{
instance=new Singleton();
}
return instance;
}
}
上述代码使用了双重锁方式较好地解决了多线程下的单例模式实现。先看内层的if语句块,使用这个语句块时,先进行加锁操作,保证只有一个线程可以访问该语句块,进而保证只创建了一个实例。再看外层的if语句块,这使得每个线程欲获取实例时不必每次都得加锁,因为只有实例为空时(即需要创建一个实例),才需加锁创建,若果已存在一个实例,就直接返回该实例,节省了性能开销。
2、饿汉模式
这种模式的特点是自己主动实例。
publicclass Singleton
{
privatestatic Singleton instance;
privatestaticobject _lock=newobject();
private Singleton()
{
}
publicstatic Singleton GetInstance()
{
if(instance==null)
{
lock(_lock)
{
if(instance==null)
{
instance=new Singleton();
}
}
}
return instance;
}
}
上面使用的readonly关键可以跟static一起使用,用于指定该常量是类别级的,它的初始化交由静态构造函数实现,并可以在运行时编译。在这种模式下,无需自己解决线程安全性问题,CLR会给我们解决。由此可以看到这个类被加载时,会自动实例化这个类,而不用在第一次调用GetInstance()后才实例化出唯一的单例对象。