為了便于說明,舉1個簡單的例子。假定現(xiàn)在有1個項目需要建立1個和銀行交互的平臺,目前只接入工商銀行,后續(xù)接入其他銀行,每一個銀行的業(yè)務都有差異,報文格式可能也不1致。
這里只羅列幾個扼要的流程,僅包括拼報文,發(fā)送報文,接收報文,解析報文,其余整體架構和后續(xù)處理等內容省略。
創(chuàng)建1個銀行交互類 BankOpt,包括4個函數(shù):
int setMsg(); //拼報文
int sendMsg(); //發(fā)送報文
int getMsg(); //接收報文
int parseMsg(); //解析報文
然后在每一個函數(shù)中通過if-else來判斷具體是哪個銀行,以后進行相應的處理。
這類設計在剛開發(fā)的時候非常方便,代碼量少,但是如果后續(xù)需要接入另外1個銀行時就需要改動BankOpt類,不符合設計模式中的開放-封閉原則。而且單個函數(shù)中將來可能會有大量的if-else,使代碼可讀性降落。
通過簡單工廠模式,我們可以創(chuàng)建1個專門的工廠類用于實例化1個適合的銀行交互類,只需要這個銀行交互類具有共同的接口便可。
首先,為了實現(xiàn)更好的復用,把各個銀行交互類中相同的部份抽象出來,構成1個銀行交互基類,代碼以下:
class BaseBank
{
public:
virtual int setMsg() = 0;
virtual int sendMsg() = 0;
virtual int getMsg() = 0;
virtual int parseMsg() = 0;
};
這里僅僅聲明了4個純虛函數(shù),具體的業(yè)務邏輯在子類中實現(xiàn)。
創(chuàng)建兩個銀行交互子類GSBank(工商銀行)和RMBank(人民銀行),繼承BaseBank,實現(xiàn)4個虛函數(shù)。
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函數(shù),用于根據(jù)銀行編碼創(chuàng)建相應的實例并返回其基類指針,這樣我們只需要通過基類指針調用相干函數(shù)便可。
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種能夠根據(jù)字符串動態(tài)獲得對應的銀行交互類的實例的方法。這樣在工廠類的createBank方法中就能夠根據(jù)字符串直接獲得對應銀行交互類的實例,而不需要再每次通過新增else if 子句來新增1個銀行接口。
也就是說,利用反射和簡單工廠模式,下次當我們需要新增1個銀行接口的時候只需要新增1個銀行交互類便可,不需要修改原來的任何代碼,實現(xiàn)了業(yè)務上的解耦。
相干代碼以下:
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函數(shù),利用Class的newInstance函數(shù)來創(chuàng)建實例:
BaseBank* createBank(const string& bank_name) {
return (BaseBank*)Class::newInstance(bank_name);
}
Class類中的m_register變量是static類型的map,相當于全局變量。
newInstance函數(shù),傳入類名,查找map,調用回調函數(shù),返回1個對應類的實例。
registerClass函數(shù)傳入類名和用于創(chuàng)建實例的回調函數(shù)并將信息存入全局的map中。
Register類只有1個構造函數(shù),會調用Class的registerClass函數(shù)完成注冊。
利用宏定義,在每個需要反射的類后面額外增加1個類,其中有1個Register類型的static const變量,這樣在程序啟動的時候就會完成初始化調用Register類的構造函數(shù),完成注冊。
以后只需要在需要反射的類,例如在工商銀行交互類 GSBank 后面加上1條宏定義:
REGISTER_CLASS(GSBank) 就能夠通過工廠類傳入”GSBank”字符串取得工商銀行交互類的實例。
通過傳入不同的銀行編碼,會實例化不同的銀行交互類,并且履行其對應的函數(shù)。
如果需要增加新的銀行接口,例如農(nóng)業(yè)銀行,只需要新增1個NYBank類,實現(xiàn)具體的業(yè)務邏輯,不需要改動原來的任何代碼,傳入NYBank字符串,就會履行農(nóng)業(yè)銀行相干的處理流程。