为了便于说明,举1个简单的例子。假定现在有1个项目需要建立1个和银行交互的平台,目前只接入工商银行,后续接入其他银行,每一个银行的业务都有差异,报文格式可能也不1致。
这里只罗列几个扼要的流程,仅包括拼报文,发送报文,接收报文,解析报文,其余整体架构和后续处理等内容省略。
创建1个银行交互类 BankOpt,包括4个函数:
int setMsg(); //拼报文
int sendMsg(); //发送报文
int getMsg(); //接收报文
int parseMsg(); //解析报文
然后在每一个函数中通过if-else来判断具体是哪个银行,以后进行相应的处理。
这类设计在刚开发的时候非常方便,代码量少,但是如果后续需要接入另外1个银行时就需要改动BankOpt类,不符合设计模式中的开放-封闭原则。而且单个函数中将来可能会有大量的if-else,使代码可读性降落。
通过简单工厂模式,我们可以创建1个专门的工厂类用于实例化1个适合的银行交互类,只需要这个银行交互类具有共同的接口便可。
首先,为了实现更好的复用,把各个银行交互类中相同的部份抽象出来,构成1个银行交互基类,代码以下:
class BaseBank
{
public:
virtual int setMsg() = 0;
virtual int sendMsg() = 0;
virtual int getMsg() = 0;
virtual int parseMsg() = 0;
};
这里仅仅声明了4个纯虚函数,具体的业务逻辑在子类中实现。
创建两个银行交互子类GSBank(工商银行)和RMBank(人民银行),继承BaseBank,实现4个虚函数。
class BankFactory
{
public:
BaseBank* createBank(const string& bank_name) {
if (bank_name == “GSBank”)
return new GSBank();
else if (bank_name == “RMBank”)
return new RMBank();
}
};
工厂类中有1个createBank函数,用于根据银行编码创建相应的实例并返回其基类指针,这样我们只需要通过基类指针调用相干函数便可。
BankFactory bf;
BaseBank* t = (BaseBank*)bf.createBank(bank_name);
if (t == NULL) {
cout << "银行编码毛病!" << endl;
return 2;
}
t->setMsg();
t->sendMsg();
t->getMsg();
t->parseMsg();
反射在java的1些框架中使用的比较多,而且用起来非常方便。C++本身其实不支持,但是我们可以摹拟1些简单的特性。
我们需要1种能够根据字符串动态获得对应的银行交互类的实例的方法。这样在工厂类的createBank方法中就能够根据字符串直接获得对应银行交互类的实例,而不需要再每次通过新增else if 子句来新增1个银行接口。
也就是说,利用反射和简单工厂模式,下次当我们需要新增1个银行接口的时候只需要新增1个银行交互类便可,不需要修改原来的任何代码,实现了业务上的解耦。
相干代码以下:
typedef void* (*register_func)();
class Class
{
public:
static void* newInstance(const string& class_name) {
map<string, register_func>::iterator it = m_register.find(class_name);
if (it == m_register.end())
return NULL;
else
return it->second();
}
static void registerClass(const string& class_name, register_func func) {
m_register[class_name] = func;
}
private:
/* key is class name and value is function to create instance of class */
static map<string, register_func> m_register;
};
class Register
{
public:
Register(const string& class_name, register_func func) {
Class::registerClass(class_name, func);
}
};
#define REGISTER_CLASS(class_name)
class class_name##Register {
public:
static void* newInstance() {
return new class_name;
}
private:
static const Register reg;
};
const Register class_name##Register::reg(#class_name,class_name##Register::newInstance);
还需要修改工厂类的createBank函数,利用Class的newInstance函数来创建实例:
BaseBank* createBank(const string& bank_name) {
return (BaseBank*)Class::newInstance(bank_name);
}
Class类中的m_register变量是static类型的map,相当于全局变量。
newInstance函数,传入类名,查找map,调用回调函数,返回1个对应类的实例。
registerClass函数传入类名和用于创建实例的回调函数并将信息存入全局的map中。
Register类只有1个构造函数,会调用Class的registerClass函数完成注册。
利用宏定义,在每个需要反射的类后面额外增加1个类,其中有1个Register类型的static const变量,这样在程序启动的时候就会完成初始化调用Register类的构造函数,完成注册。
以后只需要在需要反射的类,例如在工商银行交互类 GSBank 后面加上1条宏定义:
REGISTER_CLASS(GSBank) 就能够通过工厂类传入”GSBank”字符串取得工商银行交互类的实例。
通过传入不同的银行编码,会实例化不同的银行交互类,并且履行其对应的函数。
如果需要增加新的银行接口,例如农业银行,只需要新增1个NYBank类,实现具体的业务逻辑,不需要改动原来的任何代码,传入NYBank字符串,就会履行农业银行相干的处理流程。