- A+
所属分类:IT技术
解决问题
使用工厂模式创建对象时,会通过传入的参数进行if判断,来创建出合适的对象。另外,也引入了实现子类,这样导致在工厂创建时,必须知道子类实现细节,并且,如果再增加子类,会需要修改工厂类,增加if判断。
达到目的
工厂通过传入类名字符串,创建出需要的对象。
代码
DynOBJ.h文件
- #ifndef DYNOBJ_H
- #define DYNOBJ_H
- #include <string>
- #include <map>
- typedef void* (*Constructor)();//定义一个函数指针void* Constructor()
- //该类负责创建一个map,该map负责存储类名字符串和其对应的构造方法,
- //并提供注册和根据类名字符串创建对象的方法
- class CObjecctFactory{
- public:
- static void registerClass(std::string className, Constructor constructor){
- constructors()[className] = constructor;
- }
- static void* createObject(const std::string& className){
- Constructor constructor = NULL;
- if(constructors().find(className) != constructors().end()){
- constructor = constructors().find(className)->second;
- }
- if(!constructor)
- {
- return NULL;
- }
- return (*constructor)();//调用函数指针指向的函数,*即解引用
- }
- private:
- //<string,Constructor>:string->动态创建的类的类名,Constructor是构建函数指针
- inline static std::map<std::string, Constructor>& constructors(){
- static std::map<std::string, Constructor> instance;
- return instance;
- }
- };
- //定义一个宏,在新建类的地方调用,达到注册的目的
- #define REG_CLASS(class_name) \
- class class_name##Helper{ \
- public: \
- class_name##Helper(){ \
- CObjecctFactory::registerClass(#class_name,class_name##Helper::createObjFunc); \
- } \
- static void* createObjFunc(){ \
- return new class_name; \
- } \
- }; \
- class_name##Helper class_name##helper;
- //在这里直接实例化出每个类对应的全局对象helper,
- //自动调用helper的构造函数完成类注册
- #endif // DYNOBJ_H
该文件提供了注册类和创建对象的公共方法。
SimpleFactoryRefactor.cpp
- #include <iostream>
- #include <string>
- #include "DynOBJ.h"
- using namespace std;
- class Api{
- public:
- virtual void test(string s)=0;
- protected:
- Api(){}
- };
- class ImpleOne:public Api{
- public :
- void test(string s){
- cout<<"one is running"<<s;
- }
- };
- REG_CLASS(ImpleOne)
- class ImpleTwo:public Api{
- public :
- void test(string s){
- cout<<"two is running"<<s;
- }
- };
- REG_CLASS(ImpleTwo)//实际使用时,可以在子类定义的末尾使用注册宏
- class AutoFactory{
- public:
- static Api* createApi(){
- Api* pApi = NULL;
- //可通过配置文件存储的字符串进行自动切换配置
- //当然,如果应用在模块集成中,此处可以通过读取某个文件夹下的所有模块入口类名,
- //在这里进行动态循环创建,再通过统一的接口Api进行无差别访问,不需要知道Api的子类实现
- pApi = static_cast<Api*>(CObjecctFactory::createObject("ImpleOne"));
- return pApi;
- }
- };
- int main(void)
- {
- Api* pApi = AutoFactory::createApi();
- pApi->test(":AutoFactory");
- system("pause");
- return 0;
- }