工厂模式,想必大家都很熟悉,工厂模式封装了产品的生产,用户无需知道对象是怎么生产出来的,只要给定一个产品名称,就可以得到相应的的产品。在Java和C#中,对用相应的反射机制可以利用,很好的实现了工厂模式。但是在C++没有反射机制,怎么实现呢?下面一一详解。
在工厂中,用一个map是用来保存类名与生产者映射关系,在注册的时候将类名与对应关系设置好,生产对象和销毁对象都是以这个map为核心,用类名取得生产者,然后在用生产者获得产品。其中编程细节各位可以自己琢磨。
在这个工厂模式中,有以下优点:
1.客户端不需要知道产品怎么生产,只需要产品名称(类名),就可以得到一个对象。
2.良好的拓展性,如果需要往工厂中增加生产者时,只需要将某个类注册进去即可,无需修改代码。
3.面向接口编程的标志,定义接口后,工厂只对接口进行操作,没有关心实现,将实现与使用场景分离。
当然也有不好的地方,生产者不够灵活,只能调用无形参构造来生产对象,因为需要抽象共性,并且编程语言的局限性,利用宏来定义类,使得有形参的生产者较难实现。
工厂类中,包含了各种生产者,在语言层面,就是每个类都对应一个生产者,工厂实际是用类名索引到对应的生产者,然后调用生产者生产对象,这个是通用模型。下面我们用类图来表示,如下所示:
上图中的各个模块详解如下:
CClassFactory:用于生产对象,通过类对应的生产者进行生产。
IClassObjectProducer:生产者接口,抽象出生产者的属性。
CImpClassObjectProducer:具体的生产者,每个类对应一个生产者,通过类名索引。
CClassRegisterHelper:注册器,用于注册类的生产者到工厂类中。
首先我们来实现生产者接口,生产者一般都可以生产对象,销毁对象,获取类名。代码如下:
class IClassObjectProducer{
public:
virtual void* creatObject() = 0;
virtual void releaseObject(void** ppObject) = 0;
virtual void getClassName(__out string& strClassName) = 0;
};
有了生产者接口,我们就可以得到每个类的生产者的定义,因为每个类的生产者都具有相同的接口,我们可以用宏来实现具体的生产者,并将这个生产者注册到类中,用类名与对应的生产者形成映射关系,其实就是一一对应关系,一个类名对应一个生产者,宏定义如下:
#define REGISTER_FACTORY_CLASS(ClassName) \
class C##ClassName##producer : public IClassObjectProducer \
{ \
public: \
virtual void* creatObject(){ return new ClassName;}\
virtual void releaseObject(void** ppObject){ if ( ppObject != NULL && *ppObject != NULL){ ClassName* p = (ClassName*)*ppObject; delete(p); }}\
virtual void getClassName(__out string& strClassName){ strClassName = #ClassName;}\
}; \
static CClassRegisterHelper s_C##ClassName##RegisterHelper( new C##ClassName##producer );
在以上代码中可以看到最后一条语句,这里巧妙的利用注册器的构造函数,将生产者注册到工厂中。因静态对象在程序入口点前执行,所以无需担心。注册器代码如下:
class CClassRegisterHelper
{
public:
CClassRegisterHelper(IClassObjectProducer* pClassObjectProducer);
};
CClassRegisterHelper::CClassRegisterHelper( IClassObjectProducer* pClassObjectProducer )
{
CClassFactory::registerClassProducer(pClassObjectProducer);
}
上面通过构造注入依赖,将生产者注册到工厂中,下面我们来看看大头的工厂类的定义。代码如下:
class CClassFactory{
typedef map<string, IClassObjectProducer*> FactoryProducerMap; //类名与生产者对应的map
typedef pair<string,IClassObjectProducer*> FactoryProducerPair;
public:
static void* createClassObject(__in const string& strClassName);
static bool releaseClassObject(__inout void** ppObject, __in const string& strClassName);
static bool registerClassProducer(__in IClassObjectProducer* pClassObjectProducer);
static void resetClassFactory();
protected:
static FactoryProducerMap* ms_pMapProducers;
};
void* CClassFactory::createClassObject( __in const string& strClassName )
{
if ( NULL == ms_pMapProducers )
{
ms_pMapProducers = new FactoryProducerMap;
}
FactoryProducerMap::iterator it = ms_pMapProducers->find(strClassName);
void* pObject = NULL;
if ( it != ms_pMapProducers->end() && it->second != NULL ) //找到类对应的生产者
{
pObject = it->second->creatObject();//生产类对象
}
return pObject;
}
bool CClassFactory::releaseClassObject( __inout void** ppObject, __in const string& strClassName )
{
if ( NULL == ppObject || NULL == *ppObject || NULL == ms_pMapProducers )
{
return false;
}
if ( strClassName != "" )
{
FactoryProducerMap::iterator it = ms_pMapProducers->find(strClassName);
if ( it != ms_pMapProducers->end() && it->second != NULL )
{
it->second->releaseObject(ppObject);
*ppObject = NULL; //p指向NULL,这里就是传指针的地址才能在函数里面更改指针值,如果传指针,则改变的是副本,原指针不为NULL。
return true;
}
}
return false;
}
bool CClassFactory::registerClassProducer( __in IClassObjectProducer* pClassObjectProducer )
{
if ( NULL == ms_pMapProducers )
{
ms_pMapProducers = new FactoryProducerMap;
}
if ( pClassObjectProducer != NULL )
{
string strClassName;
FactoryProducerMap::iterator it;
pClassObjectProducer->getClassName(strClassName);
it = ms_pMapProducers->find(strClassName);
if ( ms_pMapProducers->end() == it )
{
ms_pMapProducers->insert(FactoryProducerPair(strClassName, pClassObjectProducer));
}else //删除旧的实例,插入新的对象
{
delete(it->second);
it->second = pClassObjectProducer;
}
return false;
}
return true;
}
void CClassFactory::resetClassFactory()
{
if ( NULL == ms_pMapProducers )
{
return;
}
FactoryProducerMap::iterator it;
for ( it = ms_pMapProducers->begin(); it != ms_pMapProducers->end(); ++it )
{
delete(it->second);
it->second = NULL;
}
ms_pMapProducers->clear();
if ( ms_pMapProducers != NULL )
{
delete ms_pMapProducers;
ms_pMapProducers = NULL;
}
}
各个函数详解:
/*----------------------------------------------------------------------------------------------------------------------------
函 数: virtual void* creatObject() = 0;
访问性: public
修饰词: virtual
返回值: void*:生产的对象的地址。
参 数:
描 述: 产生一个对象,返回对象指针。
历 史: 2013-8-29:创建
/*----------------------------------------------------------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------------------------------------------------------
函 数: virtual void releaseObject(void** ppObject) = 0;
访问性: public
修饰词: virtual
返回值: void
参 数: void** ppObject:要释放对象指针的地址,传指针地址进去,才能实际操作这个指针,否则操作的是副本,比如传void* p,则传递
遵循传值调用,传的是p在栈上的副本,这个副本指向原对象,可以delete,但是delete后,对形参p1 = null只是对副本置空,不会
对p置空,所有要操作p置空,则传p的地址,则*p取得p的值,然后 *p = null,就可以把实参p在函数内改变。
描 述: 产生一个对象,返回对象指针。
历 史: 2013-8-29:创建
/*----------------------------------------------------------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------------------------------------------------------
函 数: virtual void getClassName(__out string& strClassName) = 0;
访问性: public
修饰词: virtual
返回值: void
参 数: __out string& strClassName:获得producer对应的类名。
描 述: 产生一个对象,返回对象指针。
历 史: 2013-8-29:创建
/*----------------------------------------------------------------------------------------------------------------------------*/
/*-----------------------------------------------------------------CClassFactory----------------------------------------------
/*----------------------------------------------------------------------------------------------------------------------------
函 数: static void* createClassObject(__in const string& strClassName);
访问性: public
修饰词: static
返回值: void*:生产出的对象指针。
参 数: __in const string& strClassName:根据类名创建对象。
描 述: 根据类名找到producer,通过producer产生一个对象,返回对象指针。
历 史: 2013-8-29:创建
/*----------------------------------------------------------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------------------------------------------------------
函 数: static bool releaseClassObject(__inout void** ppObject, __in const string& strClassName);
访问性: public
修饰词: static
返回值: bool:成功是否返回true,反之则为false。
参 数: __inout void** ppObject:对象指针的地址,直接对指针操作。
参 数: __in const string& strClassName:根据类名释放对象。
描 述: 根据类名调用producter来销毁对象。
历 史: 2013-8-29:创建
/*----------------------------------------------------------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------------------------------------------------------
函 数: static bool registerClassProducer(__in IClassObjectProducer* pClassObjectProducer);
访问性: public
修饰词: static
返回值: bool:成功是否返回true,反之则为false。
参 数: __in IClassObjectProducer* pClassObjectProducer:producer对象指针。
描 述: 将producer注册到工厂中的map,producer本事有获取类名的接口,所有这里不用提供类名。
历 史: 2013-8-29:创建
/*----------------------------------------------------------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------------------------------------------------------
函 数: static void resetClassFactory();
访问性: public
修饰词: static
返回值: void
参 数:
描 述: 清除map中的所有项。
历 史: 2013-8-29:创建
/*----------------------------------------------------------------------------------------------------------------------------*/
/*------------------------------------------------------------CClassRegisterHelper--------------------------------------------
/*----------------------------------------------------------------------------------------------------------------------------
函 数: CClassRegisterHelper(IClassObjectProducer* pClassObjectProducer);
访问性: public
修饰词:
返回值:
参 数: IClassObjectProducer* pClassObjectProducer:注册producer到map中。
描 述: 构造函数,利用构造函数来调用Factory的注册函数,将producer对象注册到Factory中。此对象将声明为全局变量,这样就能在程序
运行前构造出producer。
历 史: 2013-8-29:创建
/*----------------------------------------------------------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------------------------------------------------------
宏 : REGISTER_FACTORY_CLASS(ClassName)
说 明: 此宏用于定义参数ClassName对应的producer。 并声明一个全局的CClassRegisterHelper
/*----------------------------------------------------------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------------------------------------------------------
原理: 在类的头文件中添加:REGISTER_FACTORY_CLASS(ClassName),表示将这个类加到工厂中。编译时将宏展开,得到类的producer。这时
实例化一个全局变量CClassRegisterHelper。在CClassRegisterHelper的构造中实例化一个producer,调用Factory的registerClassP
roducer(),将实例化在全局区的producer注册到Factory的map中,将类名ClassName与producer对应起来。在客户的就可以调用Factory
的相应函数来生产,销毁对象了。
/*----------------------------------------------------------------------------------------------------------------------------*/