C++工厂模式总结-简易版反射

2023-11-03

设计模式之factory method与c++反射
-记我曾经的误解

  Factory Method的官方解释是:
  Define an interface for creating an object, but let subclasses decide which class to instantiate. Factory Method lets a class defer instantiation to subclasses
  定义一个接口(Creater)来创建一个对象(Object),但是由子类(SubCreater)来决定要实例化哪一个对象(SubObject);
  这句话相当不好理解,很长一段时间以来我都似懂非懂,括号中的注解是我加上的,这样前后区分开来,可能对于我这样笨的人比较有效。

一.设计模式能干什么
  首先,我会摘抄两个例子,分别是“简单工厂”与“工厂方法”,看看设计模式能干什么。
参考自:
http://hobe.cnblogs.com/archive/2005/10/31/265875.aspx
http://hobe.cnblogs.com/archive/2005/11/01/266749.aspx

首先定义产品类及其子类:
class VideoWiring
{
public:
    virtual string PlayVideo()=0;
}

class VCD: public VideoWiring  
{
public:
    string PlayVideo()
    {
        return "正在播放播放VCD";
    }
}

class DVD: public VideoWiring  
{
public:
    string PlayVideo()
    {
        return "正在播放播放DVD";
    }
}

1.简单工厂
class Create
{
public:
    static VideoWiring* factory(string  VideoName)
    {
        switch(VideoName)
        {
            case "DVD":
                return new DVD();
            case "VCD":
                return new VCD();
        }
        return null;
    }
}

client端代码:
void PlayVideo()
{
     VideoWiring *vw=Create.factory("DVD");
     vw->PlayVideo();
     delete vw;
     
     vw=Create.factory("VCD");
     vw->PlayVideo();
     delete vw;
}
好处是:
1、充分利用了多态性不管什么具体产品都返回抽象产品。

2、充分利用了封装性,内部产品发生变化时外部使用者不会受到影响。       

缺点是:如果增加了新的产品,就必须得修改工厂(Factory),不满足闭合原则。

2.工厂方法
class Create
{
public:
    virtual VideoWiring* factory()=0;
}

class DVDCreate: public Create
{
    VideoWiring* factory()
    {
        return new DVD();
    }
}

class VCDCreate: public Create
{
    VideoWiring* factory()
    {
        return new VCD();
    }
}
client端代码:
void PlayVideo()
{
     VideoWiring *dvd,*vcd;
     Create *dvdCreate,*vcdCreate;
    
     dvdCreate=new DVDCreate();
     dvd=dvdCreate->factory();
     dvd->PlayVideo();
     delete dvd;
    
     vcdCreate=new VCDCreate();
     vcd=vcdCreate->factory();
     vcd->PlayVideo();
     delete vcd;
}
工厂方法克服了简单工厂的缺点,增加新的产品时,不必修改现存的代码,而只需增加新代码。满足开闭原则。

二.设计模式不能干什么
  我们注意到,简单工厂中的factory方法,用了一串switch-case语句,相当的丑陋,不仅如此,正是由于无法穷举,导致简单工厂不能满足闭合性的要求,设想一下,如果存在以下的语法:
    static VideoWiring* factory(string  VideoName)
    {
        VideoWiring *pvw = CreateInstance(VideoName);
        return pvw;
    }
问题不就解决了,也就不需要后面提到的"factory method“了,实际上,这种”名称->实例"的映射,就是大名鼎鼎的“反射”,许多语言都提供的属性,可是,非常不幸,c++没有!
  所以,即便是"factory method”,也只是试图从另外一个角度去满足闭合原则,并没有解决“名称->实例"的问题。
  考虑一个实际问题,输入为一个数据流inbuffer,可以按照固定格式,分析出它的业务类型typeid,也知道每种业务类型对应的处理类handler,那么,请问:如何应用设计模式?简单工厂能够解决吗?工厂方法呢?
  我的答案是:工厂方法不行,为什么呢,因为它把”名称->实例"的映射彻底交给了client,势必在client端要写上一长串的switch-case语句,来判断某个typeid需要创建哪个create,这与简单工厂中factory方法的switch-case真的有什么实质性差别吗?我认为没有,所以,解决之道不在于设计模式,而在于反射。

三.解决之道
  对上述问题,我的解决方法是:简单工厂+反射,固然,c++中不存在反射的语法,但是,你可以通过某种手段做到类似。
参见:
http://www.cnblogs.com/jiezhi/archive/2006/07/12/448962.html
采用的是全局变量+函数指针+map的做法,可以参考。实际上就是自己创建一个有限映射集合。

四.我曾经的误解
  很长时间以来,我一直以为工厂方法是为了解决简单工厂中那个反射问题的,现在才发现不是,至少,不是正面解决,而是避开了,因为它的目标不是为了对付一个语法问题,而是为了实现开闭原则,不应该认为设计模式能够增加新的语法特性,它是为了软件的扩展性而存在的。

附:
开闭原则就是一个软件实体在扩展性方面应该是开放的而在更改性方面应该是封闭的。
也就是说,在设计一个模块的时候,应当使这个模块可以在不被修改的前提下被扩展


================================================================================================================


工厂模式解决了很多问题,但每当需要增加一个新功能时候,需要修改工厂类,违反了开闭原则,具体为什么见:blog.sina.com.cn/s/blog_48ebca64010005of.html

文中解决工厂问题主要采用两种方法:

1、为每个功能创建一个Creator,该Creator继承自抽象Creator,用户可以使用抽象Creator创建各个功能的Creator,好处是保证了开闭原则,当新增功能时,不需要修改原来的工厂创建代码,只需要新增一个Creator,一个功能类,然后修改调用处;

若不采用此法则需要新增一个功能类,然后修改原来的工厂类,增加创建模块,违反开闭原则。

具体实现转自一位大侠的博客(blog.sina.com.cn/s/blog_48ebca64010005of.html):

首先定义产品类及其子类:
class VideoWiring
{
public:
    virtual string PlayVideo()=0;
}

class VCD: public VideoWiring  
{
public:
    string PlayVideo()
    {
        return "正在播放播放VCD";
    }
}

class DVD: public VideoWiring  
{
public:
    string PlayVideo()
    {
        return "正在播放播放DVD";
    }
}

1.简单工厂
class Create
{
public:
    static VideoWiring* factory(string  VideoName)
    {
        switch(VideoName)
        {
            case "DVD":
                return new DVD();
            case "VCD":
                return new VCD();
        }
        return null;
    }
}

client端代码:
void PlayVideo()
{
     VideoWiring *vw=Create.factory("DVD");
     vw->PlayVideo();
     delete vw;
     
     vw=Create.factory("VCD");
     vw->PlayVideo();
     delete vw;
}
好处是:
1、充分利用了多态性不管什么具体产品都返回抽象产品。

2、充分利用了封装性,内部产品发生变化时外部使用者不会受到影响。       

缺点是:如果增加了新的产品,就必须得修改工厂(Factory),不满足闭合原则。

2.工厂方法
class Create
{
public:
    virtual VideoWiring* factory()=0;
}

class DVDCreate: public Create
{
    VideoWiring* factory()
    {
        return new DVD();
    }
}

class VCDCreate: public Create
{
    VideoWiring* factory()
    {
        return new VCD();
    }
}
client端代码:
void PlayVideo()
{
     VideoWiring *dvd,*vcd;
     Create *dvdCreate,*vcdCreate;
    
     dvdCreate=new DVDCreate();
     dvd=dvdCreate->factory();
     dvd->PlayVideo();
     delete dvd;
    
     vcdCreate=new VCDCreate();
     vcd=vcdCreate->factory();
     vcd->PlayVideo();
     delete vcd;
}
工厂方法克服了简单工厂的缺点,增加新的产品时,不必修改现存的代码,而只需增加新代码。满足开闭原则。

方法一:

  1. class VideoWiring  
  2. {  
  3. public:  
  4.     virtual string PlayVideo()=0;  
  5. };  
  6.   
  7. class VCD: public VideoWiring    
  8. {  
  9. public:  
  10.     string PlayVideo()  
  11.     {  
  12.         return "正在播放播放VCD";  
  13.     }  
  14.   
  15.     static VideoWiring* factory()//-------------------------注意此行  
  16.     {  
  17.         return new VCD();  
  18.     }  
  19. };  
  20.   
  21. class DVD: public VideoWiring    
  22. {  
  23. public:  
  24.     string PlayVideo()  
  25.     {  
  26.         return "正在播放播放DVD";  
  27.     }  
  28.   
  29.     static VideoWiring* factory()//-----------------------------注意此行  
  30.     {  
  31.         return new DVD();  
  32.     }  
  33. };  
  34.   
  35. class SVCD: public VideoWiring    
  36. {  
  37. public:  
  38.     string PlayVideo()  
  39.     {  
  40.         return "正在播放播放SVCD";  
  41.     }  
  42.   
  43.     static VideoWiring* factory()//--------------------------------注意此行  
  44.     {  
  45.         return new SVCD();  
  46.     }  
  47. };  
class VideoWiring
{
public:
	virtual string PlayVideo()=0;
};

class VCD: public VideoWiring  
{
public:
	string PlayVideo()
	{
		return "正在播放播放VCD";
	}

	static VideoWiring* factory()//-------------------------注意此行
	{
		return new VCD();
	}
};

class DVD: public VideoWiring  
{
public:
	string PlayVideo()
	{
		return "正在播放播放DVD";
	}

	static VideoWiring* factory()//-----------------------------注意此行
	{
		return new DVD();
	}
};

class SVCD: public VideoWiring  
{
public:
	string PlayVideo()
	{
		return "正在播放播放SVCD";
	}

	static VideoWiring* factory()//--------------------------------注意此行
	{
		return new SVCD();
	}
};
  1. typedef void* (*Callback)();  
  2.   
  3.   
  4. const Callback ptrs[] =   
  5. {  
  6. (Callback)VCD::factory,  
  7. (Callback)DVD::factory,  
typedef void* (*Callback)();


const Callback ptrs[] = 
{
(Callback)VCD::factory,
(Callback)DVD::factory,
  1. (Callback)SVCD::factory</span>  
 (Callback)SVCD::factory</span>
  1. };  
};
  1. //下面是调用逻辑  
//下面是调用逻辑
  1. VideoWiring* items[16];  
  2.  sz= sizeof(ptrs) / sizeof(ptrs[0]);  
  3. for (int i = 0; i < sz; i++)  
  4. {  
  5. items[i] = (VideoWiring*)(ptrs[i]());  
  6. printf("%s\r\n", items[i]->PlayVideo().c_str());  
  7. }  
VideoWiring* items[16];
 sz= sizeof(ptrs) / sizeof(ptrs[0]);
for (int i = 0; i < sz; i++)
{
items[i] = (VideoWiring*)(ptrs[i]());
printf("%s\r\n", items[i]->PlayVideo().c_str());
}
  1. 若是新加一个功能,只需要新加一个类,然后实现factory方法,然后在调用处新增一个数组项就可以了,是不是OK了?  
若是新加一个功能,只需要新加一个类,然后实现factory方法,然后在调用处新增一个数组项就可以了,是不是OK了?

上面有个问题就是有太多的factory方法是类似的,怎么解决呢,我们可以使用template,定义个Creator基类

template<class T>
class bs
{
public:
static void * Create()
{
return new T;
}
};


在定义个功能类的基类:

class ko
{
public: 
virtual void PlayVideo()=0; 
};


然后功能类都继承与此类

class bs1:public bs<bs1>,public ko
{
public:
bs1()
{
a = "bs111";
}
void it(){}


void PlayVideo()
{
printf("%s\r\n", a.c_str());
}
private:
string a;
};


class bs2:public bs<bs2>,public ko
{
public:
bs2()
{
b = "bs222";
}
void PlayVideo()
{
printf("%s\r\n", b.c_str());
}


private:
string b;
};

然后定义指针数组

const Callback ptrs[] = 
{
(Callback)bs1::Create,
(Callback)bs2::Create
};

然后实例化

ko *k[16];
int sz= sizeof(ptrs) / sizeof(ptrs[0]);
for (int i = 0; i < sz; i++)
{
k[i] = (ko*)ptrs[i]();
k[i]->PlayVideo();
}

好像成功了,咋看是这样的,其实反而把bs1,bs2类引入到了客户端,暴露了细节类,还是得此失彼,此法宣告失败!终究还是没有绕开后续添加新类需要修改创建器的问题。


2、采用反射技术,当然只是简单反射。好处是新增功能类,只需要在功能类中实现反射,然后修改调用出,保证了开闭原则。

此处有2种方法可以实现(实际只有一种)

{1}[不推荐使用,太麻烦]一种是使用一个基类,在基类中折腾,借助了一些中间类,嵌入反射逻辑:此法用了很多模板定义,后续的类必须继承此类才能实现反射,具体实现参见:

http://blog.csdn.net/nighsen/article/details/6407017

具体实现如下:

定义个模板基类,所以类必须继承自该类

  1. template<class T, char name[]>    
  2. class RegisterItem  
  3. {  
  4. public:  
  5.     RegisterItem()  
  6.     {  
  7.           
  8.     }  
  9.     ~RegisterItem()  
  10.     {  
  11.    
  12.     }  
  13.   
  14.     static void* CreateInstance()  
  15.     {  
  16.         return new T;  
  17.     }  
  18.   
  19. public:    
  20.     static RegistyInfo rc;  //放到子类里面去初始化,否则会有问题  
  21. };  
template<class T, char name[]>  
class RegisterItem
{
public:
	RegisterItem()
 	{
 		
 	}
	~RegisterItem()
 	{
 
 	}

	static void* CreateInstance()
	{
		return new T;
	}

public:  
	static RegistyInfo rc;  //放到子类里面去初始化,否则会有问题
};
  1. //定义模板类中使用的静态成员结构  
//定义模板类中使用的静态成员结构
  1. typedef void* (*CreateFuntion)(void);    
  2.   
  3.   
  4.   
  5.   
  6.   
  7.   
  8. class ClassFactory    
  9. {    
  10. public:    
  11. static void* GetClassByName(std::string name);    
  12.   
  13.   
  14. static void RegistClass(std::string name,CreateFuntion method);  
  15.   
  16.   
  17. static std::map<std::string, CreateFuntion>& getMap();  
  18. };    
  19.   
  20.   
  21.  struct RegistyInfo  
  22.  {    
  23. RegistyInfo(std::string name, CreateFuntion method)    
  24. {    
  25. ClassFactory::RegistClass(name, method);    
  26. }    
  27.  };   
typedef void* (*CreateFuntion)(void);  






class ClassFactory  
{  
public:  
static void* GetClassByName(std::string name);  


static void RegistClass(std::string name,CreateFuntion method);


static std::map<std::string, CreateFuntion>& getMap();
};  


 struct RegistyInfo
 {  
RegistyInfo(std::string name, CreateFuntion method)  
{  
ClassFactory::RegistClass(name, method);  
}  
 }; 
  1. </pre><pre name="code" class="cpp">//下面是实现:  
</pre><pre name="code" class="cpp">//下面是实现:
  1. void* ClassFactory::GetClassByName( std::string name )  
  2. {  
  3. std::map<std::string,CreateFuntion>::const_iterator find;    
  4. find = ClassFactory::getMap().find(name);    
  5. if(find==ClassFactory::getMap().end())    
  6. {    
  7. return NULL;    
  8. }    
  9. else    
  10. {    
  11. return find->second();    
  12. }  
  13. }  
  14.   
  15.   
  16. void ClassFactory::RegistClass( std::string name,CreateFuntion method )  
  17. {  
  18. ClassFactory::getMap().insert(std::make_pair(name,method));  
  19. }  
  20.   
  21.   
  22. std::map<std::string, CreateFuntion>& ClassFactory::getMap()  
  23. {  
  24. static std::map<std::string, CreateFuntion> pMap;  
  25. return pMap;  
  26. }  
void* ClassFactory::GetClassByName( std::string name )
{
std::map<std::string,CreateFuntion>::const_iterator find;  
find = ClassFactory::getMap().find(name);  
if(find==ClassFactory::getMap().end())  
{  
return NULL;  
}  
else  
{  
return find->second();  
}
}


void ClassFactory::RegistClass( std::string name,CreateFuntion method )
{
ClassFactory::getMap().insert(std::make_pair(name,method));
}


std::map<std::string, CreateFuntion>& ClassFactory::getMap()
{
static std::map<std::string, CreateFuntion> pMap;
return pMap;
}
  1. //下面是功能基类定义  
//下面是功能基类定义
  1. class BaseItem  
  2. {  
  3. public:   
  4. virtual void Play() = 0;  
  5. };  
class BaseItem
{
public: 
virtual void Play() = 0;
};
  1. //下面是实际功能类定义  
//下面是实际功能类定义
  1. extern char p[];  
  2. class GMText:public RegisterItem<GMText, p>,public BaseItem  
  3. {  
  4. public:  
  5. GMText(void);  
  6. ~GMText(void);  
  7.   
  8.   
  9. void Play();  
  10. };  
extern char p[];
class GMText:public RegisterItem<GMText, p>,public BaseItem
{
public:
GMText(void);
~GMText(void);


void Play();
};
  1. //下面是实现  
//下面是实现
  1. extern char p[]="GMText";  
  2.   
  3.   
  4. RegistyInfo RegisterItem<GMText,p>::rc(p, RegisterItem<GMText, p>::CreateInstance);//看到了吧,在这边实例化的,一份子类里面就有独立的一份静态成员拷贝,每一份都需要自己初始化  
  5.   
  6.   
  7. GMText::GMText(void)  
  8. {  
  9. RegisterItem::rc;  
  10. }  
  11.   
  12.   
  13. GMText::~GMText(void)  
  14. {  
  15. }  
  16.   
  17.   
  18. void GMText::Play()  
  19. {  
  20. printf("GMText.play\r\n");  
  21. }  
extern char p[]="GMText";


RegistyInfo RegisterItem<GMText,p>::rc(p, RegisterItem<GMText, p>::CreateInstance);//看到了吧,在这边实例化的,一份子类里面就有独立的一份静态成员拷贝,每一份都需要自己初始化


GMText::GMText(void)
{
RegisterItem::rc;
}


GMText::~GMText(void)
{
}


void GMText::Play()
{
printf("GMText.play\r\n");
}
  1. // 下面是调用逻辑  
// 下面是调用逻辑
  1. BaseItem* tmp=(BaseItem*)ClassFactory::GetClassByName("GMText");   
  2. tmp->Play();  
BaseItem* tmp=(BaseItem*)ClassFactory::GetClassByName("GMText"); 
tmp->Play();

测试OK。经过此次试验我们可以发现一下问题:

(1)类模板的定义和实现必须在同一文件中,无法分离,若类模板中定义了静态变量,则需要在主程序开始处进行初始化,否则因为模板类会被多个CPP包含,就出现静态变量被多次初始化的情况,会出现xxx在xxx.obj中已经存在的问题。

(2)类模板中的基础类型定义有讲究,class <T, char name[]>中的char[]name是一种定义好的类型,使用时必须如下:

模板定义

template<class T, char name[]>

class test

//使用模板

const char q[]="demo";

test<CDemoClass, q> testObject;

只能使用int,long,int*,char []等类型,float,double不能使用,特别的char[]需要在外部定义个char a[]="test";样色的全局字符串才可以传入。

{2}避开模板,使用宏定义在每个功能类中加入反射逻辑,推荐此法,参见http://www.cnblogs.com/jiezhi/archive/2006/07/12/448962.html数据定义:

  1. </pre><p>cpp">class DynBase;  
  2. struct ReflectInfo;  
  3. bool Register(ReflectInfo* ci);  
  4. typedef void* (*funCreateObject)();  
  5.   
  6. //Assistant class to create object dynamicly  
  7. struct ReflectInfo  
  8. {  
  9. public:  
  10.     std::string Type;  
  11.     funCreateObject Fun;  
  12.   
  13.     ReflectInfo(std::string type, funCreateObject fun)  
  14.     {  
  15.         Type = type;  
  16.         Fun = fun;  
  17.         Register(this);  
  18.     }  
  19.   
  20.     ~ReflectInfo()  
  21.     {  
  22.         printf("fuck\r\n");  
  23.     }  
  24. };  
  25.   
  26. #define DEFINE_REFLECT(class_name)\  
  27. private:\  
  28.     static ReflectInfo m_cInfo;\  
  29. public:\  
  30.     static void* CreateClass##class_name(){return new class_name();};  
  31.   
  32.   
  33. #define DEFINE_REFLECT_IMP(class_name)\  
  34.     ReflectInfo (##class_name::m_cInfo)(#class_name,(funCreateObject)(##class_name::CreateClass##class_name));  
</pre><p>cpp">class DynBase;
struct ReflectInfo;
bool Register(ReflectInfo* ci);
typedef void* (*funCreateObject)();

//Assistant class to create object dynamicly
struct ReflectInfo
{
public:
	std::string Type;
	funCreateObject Fun;

	ReflectInfo(std::string type, funCreateObject fun)
	{
		Type = type;
		Fun = fun;
		Register(this);
	}

	~ReflectInfo()
	{
		printf("fuck\r\n");
	}
};

#define DEFINE_REFLECT(class_name)\
private:\
	static ReflectInfo m_cInfo;\
public:\
	static void* CreateClass##class_name(){return new class_name();};


#define DEFINE_REFLECT_IMP(class_name)\
	ReflectInfo (##class_name::m_cInfo)(#class_name,(funCreateObject)(##class_name::CreateClass##class_name));


下面是使用接口类
  1. DynBase.h  
DynBase.h

  1. //The base class of dynamic created class.  
  2. //If you want to create a instance of a class ,you must let  
  3. //the class derive from the DynBase.  
  4. class DynBase  
  5. {  
  6. public:  
  7.   
  8.     static bool Register(ReflectInfo* classInfo);  
  9.   
  10.     static void* CreateObject(string type);  
  11.   
  12. private:  
  13.     static std::map<string,ReflectInfo*> m_classInfoMap;  
  14. };  
//The base class of dynamic created class.
//If you want to create a instance of a class ,you must let
//the class derive from the DynBase.
class DynBase
{
public:

	static bool Register(ReflectInfo* classInfo);

	static void* CreateObject(string type);

private:
	static std::map<string,ReflectInfo*> m_classInfoMap;
};


  1. DynBase.cpp  
DynBase.cpp
  1. std::map< string,ReflectInfo*> DynBase::m_classInfoMap = std::map< string,ReflectInfo*>();  
  2.   
  3. bool Register(ReflectInfo* ci)  
  4. {  
  5.     return DynBase::Register(ci);  
  6. }  
  7.   
  8. bool DynBase::Register(ReflectInfo* classInfo)  
  9. {  
  10.     m_classInfoMap[classInfo->Type] = classInfo;  
  11.     return true;  
  12. }  
  13.   
  14. void* DynBase::CreateObject(string type)  
  15. {  
  16.     if ( m_classInfoMap[type] != NULL )  
  17.     {  
  18.         return m_classInfoMap[type]->Fun();  
  19.     }  
  20.     return NULL;  
  21. }  
std::map< string,ReflectInfo*> DynBase::m_classInfoMap = std::map< string,ReflectInfo*>();

bool Register(ReflectInfo* ci)
{
	return DynBase::Register(ci);
}

bool DynBase::Register(ReflectInfo* classInfo)
{
	m_classInfoMap[classInfo->Type] = classInfo;
	return true;
}

void* DynBase::CreateObject(string type)
{
	if ( m_classInfoMap[type] != NULL )
	{
		return m_classInfoMap[type]->Fun();
	}
	return NULL;
}

下面是功能类示例

xxx.h文件

  1. class GMOrange    
  2. {  
  3. public:  
  4.     GMOrange(void);  
  5.     ~GMOrange(void);  
  6.   
  7.     DEFINE_REFLECT(GMOrange)//添加此行------------只要看这边就可以-------------------------  
  8.   
  9. public:  
  10.     void Init();  
  11.   
  12.     void UnInit();  
  13. };  
class GMOrange  
{
public:
	GMOrange(void);
	~GMOrange(void);

	DEFINE_REFLECT(GMOrange)//添加此行------------只要看这边就可以-------------------------

public:
	void Init();

	void UnInit();
};
xxx.cpp文件:

  1. DEFINE_REFLECT_IMP(GMOrange)//添加此行------------只要看这边就可以-------------------------  
  2.   
  3.   
  4. GMOrange::GMOrange(void)  
  5. {  
  6.     printf("orange construct\r\n");  
  7. }  
  8.   
  9. GMOrange::~GMOrange(void)  
  10. {  
  11.     printf("orange deconstruct\r\n");  
  12. }  
  13.   
  14. void GMOrange::UnInit()  
  15. {  
  16.     printf("destroy orange\r\n");  
  17. }  
  18.   
  19. void GMOrange::Init()  
  20. {  
  21.     printf("create orange\r\n");  
  22. }  
DEFINE_REFLECT_IMP(GMOrange)//添加此行------------只要看这边就可以-------------------------


GMOrange::GMOrange(void)
{
	printf("orange construct\r\n");
}

GMOrange::~GMOrange(void)
{
	printf("orange deconstruct\r\n");
}

void GMOrange::UnInit()
{
	printf("destroy orange\r\n");
}

void GMOrange::Init()
{
	printf("create orange\r\n");
}

下面是调用示例

  1. GMApple* instance = (GMApple*)DynBase::CreateObject("GMApple");  
  2.  instance->Init();  
  3.  instance->UnInit();  
  4.  delete instance;  
GMApple* instance = (GMApple*)DynBase::CreateObject("GMApple");
 instance->Init();
 instance->UnInit();
 delete instance;
 此法经测试可用,问题是存在重复编码问题,不符合设计原则,但没办法,要自动化就得有些代价。 

若有建议欢迎留言。


总结:

1、在每个功能创建器类中定义个factory方法,返回自己new的对象,然后定义一个指针数组,调用处遍历这个数组,调用数组中的函数指针,创建对象;这样只需要做:

新增一个功能类,新增一个功能创建器类实现factory方法,在调用处增加factory方法指针,OK

2、定义个只含有factory静态方法的template类,让每个功能类继承这个template类,这样每个功能类就都有一个自己的factory,而且函数代码是一样的,克服1中的问题;这样需要做:

新增一个功能类,新增一个功能创建器类继承template类,在调研处增加此类的factory指针,OK

3、定义一个含有factory静态方法的template类,定义个静态的数据成员(这个成员是个结构体,在结构体的构造函数中加入注册类逻辑),每个功能类继承这个template类,这样每个功能类就各有一个静态数据成员,功能类需要在自己的实现中初始化这个成员,这样才能注册功能类,在调用的地方使用注册类的静态方法获取功能类指针。这样需要做:

新增一个功能类,继承template类,在功能类实现处初始化基类静态成员,在调研处字串数组中加入这个字串(通过GetXXXbyName()直接获取功能类指针),OK

4、文中最后一个办法,定义一个专门反射的类,哪个类需要反射,则假如对于的宏进行注册,使用方面。

综上 我觉得3,4是比较好用的办法,可以用在不同的场合。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C++工厂模式总结-简易版反射 的相关文章

  • c语言实现面向对象编程(const * ,* const)

    c语言实现面向对象编程 面向对象思想 封装 继承 多态 代码实现 函数签名及返回值的约定 const 重载 参考了onlyshi的博客代码 orz传送门 参考了嵌入式实践一些代码 这里就不加了 面向对象思想 面向对象编程 OOP 并不是一种
  • JavaScript的设计模式解析——工厂模式

    这几天一直在看 JavaScript高级程序设计 在第六章面向对象的程序设计中 自我感觉对于小白而而言 会一定程度的难以理解 什么意思啊 根本不明白哇等等 注意 大神请略过 小小码农 不敢妄言 首先 我们开门见山 什么是工厂模式 工厂模式能
  • 设计模式之(三)---工厂方法模式

    女娲补天的故事大家都听过吧 这个故事是说 女娲在补了天后 下到凡间一看 哇塞 风景太优美了 天空是湛 蓝的 水是清澈的 空气是清新的 太美丽了 然后就待时间长了就有点寂寞了 没有动物 这些看的到 都是静态的东西呀 怎么办 别忘了是神仙呀 没
  • C++设计模式(二)观察者模式

    1 观察者模式知识点 1 定义 定义对象间的一种一对多的依赖关系 当一个对象的状态发生改变的时候 所有依赖它的对象都得到通知并自动更新 2 动机 将一个系统分割成一系列相互协作的类有一个常见的副作用 需要维护相关对象间的一致性 我们不希望为
  • 小谈设计模式(1)—总序

    小谈设计模式 1 总序 专栏地址 开始操作 设计模式总论 设计模式是什么 组成要素 模式名称 问题描述 解决方案 效果描述 设计模式有什么作用 提供可重用的解决方案 提高代码的可读性和可维护性 促进代码的可扩展性 提高代码的灵活性和可重用性
  • 设计模式之享元模式

    一 背景 在面向对象程序设计过程中 有时会面临要创建大量相同或相似对象实例的问题 创建那么多的对象将会耗费很多的系统资源 它是系统性能提高的一个瓶颈 例如 围棋和五子棋中的黑白棋子 图像中的坐标点或颜色 局域网中的路由器 交换机和集线器 教
  • java需会(转载)

    一 基础篇 1 1 Java基础 面向对象的特征 继承 封装和多态 final finally finalize 的区别 Exception Error 运行时异常与一般异常有何异同 请写出5种常见到的runtime exception i
  • Java 多线程模式 —— Guarded Suspension 模式

    Part1Guarded Suspension 模式的介绍 我们只从字面上看 Guarded Suspension 是受保护暂停的意思 1Guarded Suspension 模式 在实际的并发编程中 Guarded Suspension
  • 设计模式 -- 工厂模式(Factory Pattern)

    简单工厂模式 Simple Factory Pattern 根据传入的参数决定实例化哪个对象 优点 不直接在客户端创建具体产品的实例 降低了耦合性 缺点 违反了开闭原则 对扩展开放 对修改关闭 不容易形成高内聚松耦合结构 每当我们增加一种产
  • 设计模式七大原则

    1 设计模式的目的 编写软件过程中 程序员面临着来自耦合性 内聚性以及可维护性 可扩展性 重用性 灵活性 等多方面的挑战 设计模式是为了让程序 软件 具有更好 1 代码重用性 即 相同功能的代码 不用多次编写 2 可读性 即 编程规范性 便
  • 设计模式(5)-适配器模式(Adapter Pattern)

    适配器模式 Adapter Pattern 顾名思义 就像变压器 转接头差不多 就像美国的生活电压是110V 中国是220V 就需要一个变压器将220V转换成110V 或者一个Type C接口想插如USB接口的东西 你就需要一个转换器 而这
  • 第12课:生活中的构建模式——想要车还是庄园

    用程序来模拟生活 从剧情中思考构建模式 与工厂模式的区别 与组合模式的区别 构建模式的模型抽象 类图 基于升级版的实现 模型说明 应用场景 故事剧情 下周就要过年了 这是 Tony 工作后的第一个春节 还是在离家这么远的北京工作 所以肯定不
  • linux内核中的设计模式

    创建型 Object Pool Object Pool模式可以提升性能 尤其是在对象的分配 初始化成本高 使用频率高 但使用时间短的情况下 对象池可以设置对象池的大小和回收时间缓存预分配的对象 NT和Linux都有简单的预分配缓存对象的机制
  • 哈工大2020软件构造Lab3实验报告

    本项目于4 21日实验课验收 更新完成 如果有所参考 请点点关注 点点赞GitHub Follow一下谢谢 2020春计算机学院 软件构造 课程Lab3实验报告 Software Construction 2020 Spring Lab 3
  • 泛型与反射机制在JDBC和Servlet编程中的实践

    写在前面 泛型与反射是java中的两种强大机制 可以很好的提高代码的灵活性和复用性 本篇文章向大家展现在JDBC和Servlet编程场景下反射和泛型技术的实践 通过灵活使用这两种机制打造 高度可复用的JDBC和Servlet代码 1 JDB
  • 设计模式详解---策略模式

    1 策略模式简介 策略模式 Strategy Pattern 是一种行为型设计模式 用于在运行时根据不同的情境选择不同的算法或策略 该模式将算法封装成独立的类 使得它们可以相互替换 而且可以独立于客户端使用它们的方式 1 1 主要角色 上下
  • 在AI技术的无情侵袭下,学学Java的23种设计模式还是非常有必要的

    目前国内80 程序员的主要工作是调用组合api实现各种业务需求 在顶层架构师设定好的框架下 做着重复且无聊的编码工作 如果未来ai被广泛应用 那么被替代的风险是很高的 比较扎心的是 其实目前用ai生成片段代码已经是各个公司比较普遍的做法了
  • 设计模式 原型模式 与 Spring 原型模式源码解析(包含Bean的创建过程)

    原创 疯狂的狮子Li 狮子领域 程序圈 2023 12 19 10 30 发表于辽宁 原型模式 原型模式 Prototype模式 是指 用原型实例指定创建对象的种类 并且通过拷贝这些原型 创建新的对象 原型模式是一种创建型设计模式 允许一个
  • 自动化测试面试题(附答案)

    1 自动化代码中 用到了哪些设计模式 单例设计模式 工厂模式 PO设计模式 数据驱动模式 面向接口编程设计模式 2 什么是断言 Assert 断言Assert用于在代码中验证实际结果是不是符合预期结果 如果测试用例执行失败会抛出异常并提供断
  • C++设计模式 --1.工厂模式和单例模式

    文章目录 1 工厂模式 简单工厂模式 工厂方法模式 抽象工厂模式 2 单例模式 懒汉式 饿汉式 1 工厂模式 简单工厂模式

随机推荐

  • 【JAVA面试题】为什么会出现4.0-3.6=0.40000001这种现象?

    这种舍入误差的主要原因是 浮点数值采用二进制系统表示 而在二进制系统中无法精确地表示分数 1 10 这 就好像十进制无法精确地表示分数 1 3 样 如果在数值计算中不允许有任何舍入误差 就应该使用 BigDecimal类 浮点数值不适用于无
  • mysql drop语句怎么用_SQL DROP 语句

    http www cnblogs com troywithblog archive 2013 05 24 3096515 html 通过使用 DROP 语句 可以轻松地删除索引 表和数据库 SQL DROP INDEX 语句 我们可以使用
  • sql delete删除的数据怎么恢复_如何恢复按下Shift + DELETE键永久删除的文件和资料夹?...

    简单删除和Shift Delete永久删除 想删除电脑上的任何文件 有以下两种方式 按 DELETE 键简单删除文件 在这种模式下 文件被移动到回收站 此时 如果我们想要恢复已删除的文件和资料夹 请打开回收站 在文件上按右键选择 还原 按
  • Proxmox VE ZFS 开启Thin Provision(精简配置)

    前言 最近在为一台PVE 的VM添加大容量磁盘时 20T 遇到out of disk 错误 遂发现 ZFS在没有开启Thin Provision前 会提前分配磁盘空间 即使一个字节也没有写入 在开启Thin Provision 后问题得到解
  • 【Unity插件】最多的插件合集

    一 前言 最近整理了一下文章 发现我分享了很多的插件 但是如果要查找某一款插件 还需要去搜索才能找到 很不方面 就想要将写过的所有的插件分享也好 教程也好 做一个汇总 然后这篇文章还会不断的更新 在有新的插件之后 熟悉我的人都知道 我对插件
  • python 逆向

    1 目标网址 https www qimingpian com finosda project pinvestment 2 抓包查看响应体 3 数据加密 4 打上断电进行调试 5 抠出代码进行运行 6 总结 function o t 就是我
  • shell sed过滤器详解

    1 Sed简介sed 是一种在线编辑器 它一次处理一行内容 处理时 把当前处理的行存储在临时缓冲区中 称为 模式空间 pattern space 接着用sed命令处理缓冲区中的内容 处理完成后 把缓冲区的内容送往屏幕 接着处理下一行 这样不
  • 怎么维护自己的电脑

    文章目录 我的电脑 日常维护措施 维护技巧 键盘 屏幕清洁 清理磁盘空间 控制温度 电脑换电池 无论是学习还是工作 电脑都是IT人必不可少的重要武器 一台好电脑除了自身配置要经得起考验 后期主人对它的维护也是决定它寿命的重要因素 你日常是怎
  • 开讲啦!0基础也能玩转飞桨开源社区

    作为cs ai学生 你是否经历过这些至暗时刻 希望快速入门深度学习 无奈网上到处都是看不懂 黑话 一遍遍计算综测小数点后四位 不断在保研边缘反复横跳 看着 洁白如新 的履历叹气 一听到 考研复试 就头皮发麻 0实习 的标签在求职时毫无竞争力
  • 主变压器新装或大修后投入运行为什么有时气体继电器会频繁动作?遇到此类问题怎样判断和处理?

    主变压器新装或大修后投入运行为什么有时气体继电器会频繁动作 遇到此类问题怎样判断和处理 答 新装或大修的变压器在加油 滤油时 会将空气带入变压器内部 若没有能够及时排出 则当变压器运行后油温会逐渐上升 形成油的对流 将内部贮有的空气逐渐排除
  • 个人信息可携带权的中国路径(线上)研讨会

    个人信息保护法 将于今年11月1日正式实施 其中首次提出了个人信息可携带权的相关法条 体现了将个人信息权利还于个人的立法思路 也为进一步释放数据要素生产力带来了新的历史机遇 为深入了解个人信息可携带权在全球范围的发展及在中国的可行落地路径
  • lstm(三) 模型压缩lstmp

    lstmp结构 对于传统的lstm而言 i t W i
  • Linux专栏(二):创建虚拟机与Ubuntu安装

    文章目录 1 下载Ubuntu20 04镜像 2 创建虚拟机 3 安装Ubuntu系统 本文将介绍在VMware中如何创建虚拟机并安装Ubuntu20 04系统 1 下载Ubuntu20 04镜像 下载地址 Ubuntu官网镜像下载 2 创
  • 复旦NLP团队发布80页大模型Agent综述,一文纵览AI智能体的现状与未来

    来源 机器之心 智能体会成为打开 AGI 之门的钥匙吗 复旦 NLP 团队全面探讨 LLM based Agents 近期 复旦大学自然语言处理团队 FudanNLP 推出 LLM based Agents 综述论文 全文长达 86 页 共
  • block(块),page(页),buffer cache(块缓冲)区别与联系

    在自己的理解里 块就是用来管理磁盘空间的 就像我们在给一个磁盘建立文件系统时候 我们可以指定block size 而页是针对内存管理 例如从磁盘读出的数据就缓存在内存页中 但突然对关buffer cache block buffer 这些东
  • vue项目实现搜索功能

    使用vue框架实现以下要求 1 点击 首页 顶部搜索框 通过路由跳转到搜索页 并实现关键字模糊搜索功能 2 搜索页和首页下面用到的JSON数据自行模拟 并正确搜索渲染出来 3 在搜索页保留每次的搜索历史关键字 在搜索页的 历史搜索 中显示出
  • 微信小程序wx.request 使用 post方式传参

    参考网址 https blog csdn net lengxin337 article details 78234503 重点注意 method 是 get 方式的时候 header为 Content Type application js
  • 产品不快,你就死定了!

    作者碎碎念 创业团队做产品要拼迭代速度 天下武功 唯快不破 扎克伯格说 不酷 你就死定了 我要套用他的话说 不快 你就死定了 因为太阳底下没有新鲜事 聪明人辣么多 凭空想出一个绝世好点子 你没戏的 但是 发现别人做得不足的地方 再迅速赶超
  • java.net.SocketException:Connection reset

    背景 HttpClient远程调用HTTPS的API时 报错java net SocketException Connection reset 原因 Jdk版本差异导致的异常 由于Jdk1 7默认的是TLS的协议版本是v1 0 而Jdk1
  • C++工厂模式总结-简易版反射

    设计模式之factory method与c 反射 记我曾经的误解 Factory Method的官方解释是 Define an interface for creating an object but let subclasses deci