5.1 缘由
单实例类,其作用类似于全局变量,实现的方法有很多,如CEF3的一些代码中就直接使用的全局变量,不过这个全局变量是在一个未命名的namespace里面定义的.在Loki库里面也对单件模式也有非常翔实的描述,但是那个太多,太大,我个人觉得反而将单实例类的概念淹没了.
试想一下,如果实现一个通用的单实例设备出来,通过引用这个设备,我们就可以方便的生产出单实例类.碰到这种问题我们首先的想法就是:构造一个基类,这个基类中有一个用于指代单实例子类的静态指针成员,还有一些静态函数.但事实上是,一旦你这样去做会碰到很多的问题,导致根本无法实行我们的想法.
到这里,如果没有别的想法,我们肯定又会投向Marco的怀抱了.但是这次不一样了,我们有了新的解决方案,比宏更好用,而且有绝佳的正交性.
5.2 源码及说明
其实这里,我们还是沿用了我们最初的想法,我们又通过模板的使用克服了这个想法中的重重难关,使之成为现实:
<文件:Fade\Singleton\Singleton.h>
/************************************************************************
Author:Tanglx
Date:2017/10/12
FileName:Singleton.h
Describe:
************************************************************************/
#ifndef _FADE_SINGLETON_
#define _FADE_SINGLETON_
template<class _ty>
class CSingleton{
protected:
CSingleton(){}
public:
virtual ~CSingleton(){}
static _ty* InitInstance(){
if (m_pThiss) throw NULL;
m_pThiss=new _ty;
return m_pThiss;
}
static void DestoryInstance(){
if (m_pThiss){
delete m_pThiss;
m_pThiss=NULL;
}
}
static _ty* GetInstance(){
if (!m_pThiss) throw NULL;
return m_pThiss;
}
private:
static _ty* m_pThiss;
};
template<class _ty>
_ty* CSingleton<_ty>::m_pThiss=NULL;
#endif
观看上述代码,看看模板为我们解决了什么问题
1.解决了在基类中无法定义子类的静态指针成员的问题(因为子类都是未知的)
2.模板参数的不同,就代表不同的类,说明该模板类正好能为某一个子类提供一个唯一的基类,以及一个唯一的静态指针成员
3.由于不需要知道子类,所以该模板类不需要包含子类声明,而仅仅需要子类包含该模板类声明
上面三点,看不明白就算了,我感觉我都有点描述不清楚...但是又不想长篇累牍的去描述.就这样吧,反正这个不重要.
关于这个模板类的说明,我们可以看到模板类包含哪些东西:
1.一个指向类型参数_ty的静态成员指针,这个指针用于保存子类对象的索引
2.静态函数InitInstance,该函数用于初始化单实例类
3.静态函数DestoryInstance,该函数用于销毁单实例类
4.静态函数GetInstance,该函数用于获取单实例类指针
上述代码可以看到,在InitInstance中如果m_pThiss不为空就直接throw null了,而又没有去处理这个异常.这会让程序直接崩溃.这里再话痨一下,今天不知怎的,话多...
对于错误处理,我有一个概念是这样的:严己宽人.这里的己和人,分别指的是两种错误:
1.纯代码的错误,比如某些只能调用一次的函数,调用了两次.,这种错误,我称之主观错误
2.客观性错误,比如打开文件,或者访问网站的错误,这种错误是客观性的.无法通过修改代码来达到修正错误
对待主观性错误,我们应当立即抛出异常,让程序崩溃,而对待客观性错误,我们应当去做容错处理
当然,在敏捷开发中,或者说首次开发中,我们对待错误都应该直接抛出异常,让程序崩溃.在后面的修缮中,再来分辨主观错误和客观错误,然后对客观错误进行容错处理.
5.3 使用
#include "Fade/Singleton/Singleton.h"
#include "stdio.h"
class Test:public CSingleton<Test>
{
public:
void ShowMsg(){
printf("ShowMsg\r\n");
}
};
int main()
{
Test::InitInstance();
Test* p=Test::GetInstance();
p->ShowMsg();
Test::DestoryInstance();
return 0;
}
如上述代码所示:类Test只需要派生于CSingleton<Test>,即可摇身一变成为一个单实例类.如此可方便的生成多个单实例类,而且负责实现单实例功能的代码<CSingleton>,同Test中的逻辑代码不会有一丝一毫的耦合,其正交性绝佳.
多说一句:如果一个项目里面有多个数据需要使用单实例类,我希望的是根据逻辑划分创建多个单实例类.我见过有的项目,通过一个单实例类管理所有的数据的,那个类叫GlobalDataManager,那真的是十分的混乱.
5.4 小结
本小结介绍了一种实现单实例的方法,简单易用,且效果良好.从此可以摆脱通过Marco来实现单实例类的尴尬了.而且该模板类设计的非常具有技巧性,可以体现个人逼格,由于本人今天话比较多,写了很多无关紧要的语句,后面再回头来看的时候再看看那些需要精简吧