C++工厂模式总结(简易版反射)
来源:互联网 发布:mac os 优化 编辑:程序博客网 时间:2024/06/05 15:14
工厂模式解决了很多问题,但每当需要增加一个新功能时候,需要修改工厂类,违反了开闭原则,具体为什么见: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:
}
class VCD: public VideoWiring
{
public:
}
class DVD: public VideoWiring
{
public:
}
1.简单工厂
class Create
{
public:
}
client端代码:
void PlayVideo()
{
}
好处是:
1、充分利用了多态性不管什么具体产品都返回抽象产品。
2、充分利用了封装性,内部产品发生变化时外部使用者不会受到影响。
缺点是:如果增加了新的产品,就必须得修改工厂(Factory),不满足闭合原则。
2.工厂方法
class Create
{
public:
}
class DVDCreate: public Create
{
}
class VCDCreate: public Create
{
}
client端代码:
void PlayVideo()
{
}
工厂方法克服了简单工厂的缺点,增加新的产品时,不必修改现存的代码,而只需增加新代码。满足开闭原则。
方法一:
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();}};
typedef void* (*Callback)();const Callback ptrs[] = {(Callback)VCD::factory,(Callback)DVD::factory,
(Callback)SVCD::factory</span>
};
//下面是调用逻辑
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());}
若是新加一个功能,只需要新加一个类,然后实现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
具体实现如下:
定义个模板基类,所以类必须继承自该类
template<class T, char name[]> class RegisterItem{public:RegisterItem() { }~RegisterItem() { }static void* CreateInstance(){return new T;}public: static RegistyInfo rc; //放到子类里面去初始化,否则会有问题};
//定义模板类中使用的静态成员结构
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); } };
</pre><pre name="code" class="cpp">//下面是实现:
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;}
//下面是功能基类定义
class BaseItem{public: virtual void Play() = 0;};
//下面是实际功能类定义
extern char p[];class GMText:public RegisterItem<GMText, p>,public BaseItem{public:GMText(void);~GMText(void);void Play();};
//下面是实现
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");}
// 下面是调用逻辑
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数据定义:
</pre><p>cpp">class DynBase;struct ReflectInfo;bool Register(ReflectInfo* ci);typedef void* (*funCreateObject)();//Assistant class to create object dynamiclystruct 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));
下面是使用接口类
DynBase.h
//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;};
DynBase.cpp
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文件
class GMOrange {public:GMOrange(void);~GMOrange(void);DEFINE_REFLECT(GMOrange)//添加此行------------只要看这边就可以-------------------------public:void Init();void UnInit();};xxx.cpp文件:
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");}
下面是调用示例
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是比较好用的办法,可以用在不同的场合。
- C++工厂模式总结-简易版反射
- C++工厂模式总结(简易版反射)
- 简单工厂模式,抽象工厂模式,反射工厂模式的代码总结
- 简单工厂模式,抽象工厂模式,反射工厂模式的代码总结
- 简单工厂模式,抽象工厂模式,反射工厂模式的代码总结
- 简单工厂模式,抽象工厂模式,反射工厂模式的代码总结
- 简单工厂模式,抽象工厂模式,反射工厂模式的代码总结
- 工厂模式 (C#)
- 工厂模式(C++)
- 工厂模式(C++)
- 工厂模式(C++)
- 工厂模式(与反射方法结合)
- 工厂模式(java反射的使用)
- 反射工厂模式
- 工厂模式 + 反射改进
- 工厂模式与反射
- 抽象工厂模式+反射
- 反射工厂模式
- linux中ctrl+z和ctrl+c的区别
- oracle创建一个一般用户
- COM应用和原理摘自大神
- Ajax应用
- 回收站的文件被杀毒软件清空了怎么办
- C++工厂模式总结(简易版反射)
- CSS样式表
- VS2010中使用TinyXML
- 【数据结构】算法复杂度
- 用链表实现栈
- spring注解配置详解
- POJ - 1005 I Think I Need a Houseboat
- 自由拖动的div层
- Java Swing界面编程(15)---JScrollPane