注:今天不知道怎么的CSDN的博客贴代码和贴图片的按钮好像有点问题,我贴不出来,只能用复制代码说明问题了
至于单例模式,是设计模式中最为基本的模式之一,说直白点就是在程序中确保任何时候都只有一个实例,比如windows的文件管理类,还有就是在cocos2dx中的游戏导演类等等,那么如何来确保任何时候都只能有一个实例勒?这个时候我们的static就起作用了!
前几天一个朋友问我cocos2dx中的这一行代码是什么意思,为什么要这么写,代码如下:
CCSize visibleSize = CCDirector::sharedDirector()->getVisibleSize();
他是这么问的:为什么不实例一个对象来调用成员函数,而每次调用都要把CCDirector::sharedDirector()加上去,这样岂不是很麻烦?
是的,这样是麻烦了点,但是相比他给我们带来的好处,这点麻烦就不值一提了,他保证了在整个程序运行期间只有一个实例,不会有其他对象产生,一则节省了空间,二则为我们的管理提供了方便!
单例模式的实现,在这里我模拟一个CCDirector,代码如下:
class CCDirector
{
private:
static CCDirector *pDirector;
. .......
. .......
public:
static CCDirector* sharedDirector();
{
.........
return pDirector;
}
.......
};
显然这样的类声明就达到了上面那条语法的标准,那么我们该怎么来实例化这个唯一的实例勒?在这里有两个可选模式:
懒汉式:是典型的以时间换取空间的例子,就是每次获取实例时都要进行判断,看是否要创建实例,浪费判断时间。当然如果一直没有人用的话,就不会创建实例,则是节约空间。
饿汉式:是典型的以空间换取时间,就是说当类装载的时候,就创建出一个实例,不管你用不用它,然后每次调用时就不用判断了,节省了运行时间
至于这两个模式到底哪个好,这就得自己进行时空权衡了,各有优点!
在cocos2dx中,他是使用的懒汉式实例化单一对象,代码如下:
CCDirector* CCDirector::sharedDirector(void)
{
static bool s_bFirstUseDirector = true;
if (s_bFirstUseDirector)
{
s_bFirstUseDirector = false;
s_SharedDirector.init();
}
return &s_SharedDirector;
}
可以看到他定义一个static的bool变量来标记是否创建单例对象,没有就init()一个,有就直接返回(但是我不理解的是为什么非要加个bool,这不是多占用几个字节吗,可以直接判断那个指针是否为空啊!!好吧,cocos开发团队的高瞻远瞩,我不能体会)!
至于饿汉式,就是直接刚开始的时候调用init()函数,使这个对象指针一直存在!就不用每次判断了
使用单例模式的注意点:
1:只能用实例指针吗?不能实例对象吗?
这个在很低级的书上就讲到了,我记得没错的话,谭浩强的书上都说过:结构体之中不能含有本身的结构体变量,当然可以含有指向本身结构体的指针!所以在类中当然也是一样啊,这种低级错误在新手里面可是很常见!
2:单例模式只是为了节省资源吗?
首先要说明的是,在一些情况下使用单例模式是可以达到节省资源的目的,但是单例模式的意图不只是为了节省资源,如果仅仅为了节省资源就使用单例模式的话可能造成单例模式的滥用。单例模式是为了确保在整个应用期间只有一个实例,以达到用户的特定的使用目的。
3:单例模式的坏处
扩展困难,由于sharedDirector静态函数没有办法生成子类的实例。如果要拓展,只有重写那个类。
隐式使用引起类结构不清晰。比如有时候,你并不知道某个类A是单例类,当你读类B的时候,你可能先看它头文件,或者类视图里的内容,从这里你无法知道A和B 关系,因为B类在实现的时候才使用A类的那个所谓的sharedDirector函数,读不到这行,你就不会知道B类对A类的依赖关系。
导致程序内存泄露的问题。很多人只是调用了sharedDirector生成唯一的实例,却永远new被封装在sharedDirector里忘了去释放内存。
4: 什么情况下不能用单例模式
单例模式简单易用,但是也是所有设计模式中最容易滥用的模式。当你的类想得到很好的扩展时,不能使用单例模式。
也许你的程序一开始并非一定要确保只有一个实例,如果你仅仅是为了节省资源而用的话,这个时候要慎用,因为随着时间的推延也许你的程序还需要扩展。