C++ 通过模版工厂实现 简单反射机制
前言
我們知道Java/Python這種語言能夠很好得 支持反射。反射機制 就是一種用戶輸入的字符串到對應實現方法的映射,比如http接口中 用戶傳入了url,我們需要調用該url對應的方法/函數對象 從而做出對應的操作。
而C++ 并沒有友好得支持這樣的操作,而最近工作中需要通過C++實現http接口,這個過程想要代碼實現得優雅一些,就需要實現這樣的功能。
最終的實現結果就是:
int main() {Initial();JudgeName jm;auto res = jm.Judge("Zhang");res->ShowName();return 0;
}
我們只需要通過輸入一個字符串,就能得到一個字符串對應的類的對象,從而調用該對象對應的方法。
實現過程
-
實現模版工廠
反射機制本身是依賴工廠模式實現的,也就是提供一個創建函數對象的工廠,能夠創建各種類型的函數對象。
這里面的各種類型 – 其實就需要實現一個通用的模版工廠來達到創建各種類型的目的。// 工廠類模版,創建各種類型的類對象 template <class OperationType_t> class OperationFactory { public:// 創建一個工廠單例,只會有一個對象工廠static OperationFactory<OperationType_t>& Instance() {static OperationFactory<OperationType_t> instance;return instance;}private:// We don't allow to constructor, copy constructor and align constructorOperationFactory() = default;~OperationFactory() = default;OperationFactory(const OperationFactory&) = delete;const OperationFactory& operator= (const OperationFactory&) = delete;}; -
實現類的對象到類名的映射。
我們實現了能夠創建所有類對象的函數工廠,但是還需要將創建好的對象和他們的類名字對應起來,做一個映射。
在模版工廠類中補充映射邏輯:// Factory class template template <class OperationType_t> class OperationFactory { public:// Single pattern of the factorystatic OperationFactory<OperationType_t>& Instance() {static OperationFactory<OperationType_t> instance;return instance;}// 類名 和 類對象的映射void RegisterOperation(const std::string& op_name,OperationRegister<OperationType_t>* reg) {operationRegister[op_name] = reg;}// 獲取指定類名字 對應的 對象// 也就是從映射map中查找OperationType_t* GetOperation(const std::string& op_name) {if (operationRegister.find(op_name) != operationRegister.end()) {return operationRegister[op_name]->CreateOperation(op_name);}return nullptr;}private:// We don't allow to constructor, copy constructor and align constructorOperationFactory() = default;~OperationFactory() = default;OperationFactory(const OperationFactory&) = delete;const OperationFactory& operator= (const OperationFactory&) = delete;// 類名字 和 類對象之間的映射std::map<std::string, OperationRegister<OperationType_t>* > operationRegister; }; -
實現一個注冊類
此時 我們通過這個注冊類的入口 將類名 和類的對象完整映射起來。template <class OperationType_t> class OperationRegister { public:virtual OperationType_t* CreateOperation(const std::string& op_name) = 0;protected:OperationRegister() {}virtual ~OperationRegister() {} };// 注冊一個以基類的子類對象。 template <class OperationType_t, class OperationImpl_t> class OperationImplRegister : public OperationRegister<OperationType_t> { public:// 獲取一個基類的工廠explicit OperationImplRegister(const std::string& op_name) {OperationFactory<OperationType_t>::Instance().RegisterOperation(op_name, this);}// 獲取這個基類對應的子類對象OperationType_t* CreateOperation(const std::string& op_name) {return new OperationImpl_t(op_name);} };
應用
有了上面的模版工廠 以及 注冊類名字 和 類的映射模版,接下來我們看看怎么使用:
我們實現了如下一個父類 以及 幾個父類對應的子類實現
class Father {
public:virtual std::string Name() = 0;virtual void ShowName() = 0;
};class Wang : public Father{
public:Wang(const std::string& name) : name_(name){}std::string Name() override { return name_; }void ShowName() override { cout << "Name: " << name_ << endl; }private:std::string name_;
};class Zhang : public Father {
public:Zhang(const std::string& name) : name_(name) {}std::string Name() override { return name_; }void ShowName() override { cout << "Name: " << name_ << endl; }private:std::string name_;
};class Li : public Father {
public:Li(const std::string& name) : name_(name) {}std::string Name() override { return name_; }void ShowName() override { cout << "Name: " << name_ << endl; }private:std::string name_;
};
接下來需要統一注冊一下這幾個子類 的 名字 以及他們的對象:
// Construct the string name with there object's map
void Initial() {static bool init = false;if (init == false) {static OperationImplRegister<Father, Wang> wang("Wang");static OperationImplRegister<Father, Zhang> zhang("Zhang");static OperationImplRegister<Father, Li> li("Li");init = true;}
}
最后就是一個通過字符串 獲取對象
class JudgeName {
public:JudgeName(){}Father* Judge(const std::string& name) {OperationFactory<Father>& fac = OperationFactory<Father>::Instance();return fac.GetOperation(name);}
};
這個類的函數中,我們用戶只需要傳入一個字符串,就能夠得到這個字符串的類的對象,從而進行后續的對象方法相關的操作。
能夠極大得簡化我們的if-else if 這樣的分支代碼,同時提升了代碼的可擴展性。用戶只需要繼續補充想要使用的類,并將這個類的名字和對象注冊到映射map中就好了,后續只需要使用類名就能夠創建出這個類的對象。
完整代碼實現
#include <iostream>
#include <map>using namespace std;// Register the operation
// The 'OperationTyple_t' is the abstract class
template <class OperationType_t>
class OperationRegister {
public:virtual OperationType_t* CreateOperation(const std::string& op_name) = 0;protected:OperationRegister() {}virtual ~OperationRegister() {}
};// Factory class template
template <class OperationType_t>
class OperationFactory {
public:// Single pattern of the factorystatic OperationFactory<OperationType_t>& Instance() {static OperationFactory<OperationType_t> instance;return instance;}void RegisterOperation(const std::string& op_name,OperationRegister<OperationType_t>* reg) {operationRegister[op_name] = reg;}OperationType_t* GetOperation(const std::string& op_name) {if (operationRegister.find(op_name) != operationRegister.end()) {return operationRegister[op_name]->CreateOperation(op_name);}return nullptr;}private:// We don't allow to constructor, copy constructor and align constructorOperationFactory() = default;~OperationFactory() = default;OperationFactory(const OperationFactory&) = delete;const OperationFactory& operator= (const OperationFactory&) = delete;std::map<std::string, OperationRegister<OperationType_t>* > operationRegister;
};// An template class to create the detail Operation
template <class OperationType_t, class OperationImpl_t>
class OperationImplRegister : public OperationRegister<OperationType_t> {
public:explicit OperationImplRegister(const std::string& op_name) {OperationFactory<OperationType_t>::Instance().RegisterOperation(op_name, this);}OperationType_t* CreateOperation(const std::string& op_name) {return new OperationImpl_t(op_name);}
};class Father {
public:virtual std::string Name() = 0;virtual void ShowName() = 0;
};class Wang : public Father{
public:Wang(const std::string& name) : name_(name){}std::string Name() override { return name_; }void ShowName() override { cout << "Name: " << name_ << endl; }private:std::string name_;
};class Zhang : public Father {
public:Zhang(const std::string& name) : name_(name) {}std::string Name() override { return name_; }void ShowName() override { cout << "Name: " << name_ << endl; }private:std::string name_;
};class Li : public Father {
public:Li(const std::string& name) : name_(name) {}std::string Name() override { return name_; }void ShowName() override { cout << "Name: " << name_ << endl; }private:std::string name_;
};// Construct the string name with there object's map
void Initial() {static bool init = false;if (init == false) {static OperationImplRegister<Father, Wang> wang("Wang");static OperationImplRegister<Father, Zhang> zhang("Zhang");static OperationImplRegister<Father, Li> li("Li");init = true;}
}class JudgeName {
public:JudgeName(){}Father* Judge(const std::string& name) {OperationFactory<Father>& fac = OperationFactory<Father>::Instance();return fac.GetOperation(name);}
};int main() {Initial();JudgeName jm;auto res = jm.Judge("Zhang");res->ShowName();return 0;
}
總結
以上是生活随笔為你收集整理的C++ 通过模版工厂实现 简单反射机制的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 求一个胖的个性签名
- 下一篇: 手把手教你 用C++实现一个 可持久化