一、首先了解下单例:
单例 Singleton 是设计模式的一种,其特点是只提供唯一一个类的实例,具有全局变量的特点,在任何位置都可以通过接口获取到那个唯一实例;
具体运用场景如:
- 设备管理器,系统中可能有多个设备,但是只有一个设备管理器,用于管理设备驱动;
- 数据池,用来缓存数据的数据结构,需要在一处写,多处读取或者多处写,多处读取;
如何满足上述情景的需求?
- 全局只有一个实例:static 特性,同时禁止用户自己声明并定义实例(把构造函数设为 private)
- 线程安全
- 禁止赋值和拷贝
- 用户通过接口获取实例:使用 static 类成员函数
有两种模式,饿汉和懒汉模式。
- 懒汉式(Lazy-Initialization)的方法是直到使用时才实例化对象,也就说直到调用get_instance() 方法的时候才 new 一个单例的对象。好处是如果被调用就不会占用内存。
- 饿汉的方法是在声明时就实例化对象。
我们采用饿汉的模式来做示例。
singleton.h
#ifndef SINGLETON_H
#define SINGLETON_H
template <typename T>
class Singleton
{
private:
/** \brief Explicit private copy constructor. This is a forbidden operation.*/
Singleton(const Singleton<T> &);
/** \brief Private operator= . This is a forbidden operation. */
Singleton& operator=(const Singleton<T> &);
protected:
static T* msSingleton; //静态的受保护的对象指针
public:
Singleton(void)
{
if (msSingleton) { //如果该对象已创建就不再创建
return;
}
#if defined( _MSC_VER ) && _MSC_VER < 1200
int offset = (int)(T*)1 - (int)(Singleton <T>*)(T*)1;
msSingleton = (T*)((int)this + offset);
#else
msSingleton = static_cast< T* >( this );
#endif
}
virtual ~Singleton(void)
{
msSingleton = 0;
}
static T& getSingleton(void)
{
return (*msSingleton);
}
static T* getSingletonPtr(void)
{
return msSingleton;
}
};
上述模板主要是为了使继承它的类具有成为单例的功能,构造函数将已经实例化的对象T static_cast< T* >( this );后赋值给msSingleton,通过提供的getSingleton来获取。
二、如何使用单例模板
步骤如下:
- 要单例化的类继承该模板类
- 声明并初始化静态成员msSingleton
- 实例化对象
三、简单工厂模式
工厂顾名思义就是创建产品,根据产品是具体产品还是具体工厂可分为简单工厂模式和工厂方法模式,根据工厂的抽象程度可分为工厂方法模式和抽象工厂模式。单例化的简单工厂可以供多用户使用。并制造自己需要的产品。
四、单例简单工厂应用
我们的应用场景是
2. 数据池,用来缓存数据的数据结构,需要在一处写,多处读取或者多处写,多处读取;
这个数据池也就是内存池,而且他比较特殊,并不止一个内存池,而是有多个,我们使用单例工厂来给需要的用户分配空闲的内存池对象。
内存类:
class MemoryPool
{
public:
MemoryPool()
{
printf("memerypool instruction\n");
}
~MemoryPool()
{
printf("memerypool distruction\n");
}
void PreAlloc(int num, int size)
{
printf("PreAlloc \n");
}
uint8_t* AllocMemory(int datalen)
{
printf("alloc memery\n");
}
bool FreeMemory(uint8_t* mem)
{
printf("free memory \n");
}
}
单例工厂类
class memoryPoolFactory: public Singleton<memoryPoolFactory>
{
public:
MemoryPool* createInstance(int id){
MemoryPool* p_memPool;
std::map<int,MemoryPool*>::iterator iter;
iter = m_mempoolMap.find(id);
if(iter != m_mempoolMap.end())
{
printf("Allready create memoryPool.\n");
return iter->second;
}
else
{
p_memPool = new MemoryPool();
p_memPool->PreAlloc(20,900*1024);
m_mempoolMap[id] = p_memPool;
}
return m_mempoolMap[id];
}
MemoryPool* getInstance(int id)
{
std::map<int,MemoryPool*>::iterator it;
it = m_mempoolMap.find(id);
if(it != m_mempoolMap.end())
{
return m_mempoolMap[id];
}
else
{
printf("Fail to find memoryPool .\n");
return NULL;
}
}
private:
std::map<int,MemoryPool*> m_mempoolMap;
};
template <> memoryPoolFactory* Singleton<memoryPoolFactory>::msSingleton = 0;
void main()
{
memoryPoolFactory* mempoolFactory = new memoryPoolFactory();
//下面可以在另一个类中调用
mempoolFactory = memoryPoolFactory::getSingletonPtr();
if(mempoolFactory == NULL)
{
LOGI(LOG_HIPC,"Get memoryPoolFactory Failly .\r\n");
return;
}
p_memoryPool = mempoolFactory->createInstance(ID); //创建共享内存池
if(p_memoryPool == NULL)
{
LOGI(LOG_HIPC,"Get memoryPool Failly . \n");
return;
}
memPoolFactory = memoryPoolFactory::getSingletonPtr();
MemoryPool *p_memPool = NULL;
p_memPool = memPoolFactory->getInstance(ID);
if(p_memPool == NULL)
{
LOGI(TAG_SENDER ,"ERROR p_memPool null ==================");
}
//然后就可以通过p_memPool调用到内存池的方法了。
}
通过std::map<int,MemoryPool*> m_mempoolMap;来管理这些内存池对象,一个对象对应一个ID。这样就可以批量去管理内存池对象了。
有不明白的地方可以评论。最后的用例应该是在多个不同的类里使用单例工厂对象。这里我偷懒了。你们可以自行根据需要修改。