598 字
3 分钟
通过 RIME 学习 C++ 系列:4
组件的注册与调用
在阅读 librime 的代码过程中,发现不同功能之间调用,是通过组件注册形式来发现与调用的。
所谓组件指 ComponentBase 的子类,代码在:src/rime/component.h 中。
而组件的注册相关管理是指 Registry,代码在:src/rime/registry.h 中。
程序运行时,将全部组件注册到 Registry 的 map 结构中,当需要调用时,在从 Register 中取出相关组件。
我们通过一个 Example 代码说明:
#include <map>#include <string>
using std::map;using std::string;
template <typename T>using an = std::shared_ptr<T>;
template <typename T>using the = std::unique_ptr<T>;
class ComponentBase;
class Registry {public: using ComponentMap = map<string, an<ComponentBase>>;
an<ComponentBase> find(const string& name); void registerComponent(const string& name, an<ComponentBase> component); void unregisterComponent(const string& name); void clear();
static Registry& instance();
private: Registry() = default;
ComponentMap map_;};Registry 代码没有什么特别的,就是组件的注册/发现相关函数。唯一需要注意的是,Registry 是单例模式。
Registry& Registry::instance() { static the<Registry> instance_; if (!instance_) { instance_ = the<Registry>(new Registry()); } return *instance_;}
an<ComponentBase> Registry::find(const string& name) { auto it = map_.find(name); if (it != map_.end()) { return it->second; } return nullptr;};
void Registry::registerComponent(const string& name, an<ComponentBase> component) { if (auto oldComponent = find(name)) { oldComponent.reset(); } map_[name] = component;}
void Registry::unregisterComponent(const string& name) { auto it = map_.find(name); if (it == map_.end()) { return; } it->second.reset(); map_.erase(it);}组件的代码需要细细咀嚼,仔细阅读可以发现 C++ 与其他编程语言与众不同的地方。
#include "registry.hpp"
class ComponentBase {public: ComponentBase() = default; virtual ~ComponentBase() = default;};
template <typename T, typename Arg>struct Class { using Initializer = Arg;
class Component : virtual public ComponentBase { public: virtual an<T> create(Initializer arg) = 0; };
static an<Component> require(const string& name) { return dynamic_pointer_cast<Component>(Registry::instance().find(name)); }};
template <typename T>struct Component : public T::Component {public: an<T> create(typename T::Initializer args) { return std::make_shared<T>(std::forward<typename T::Initializer>(args)); }};要实现一个 Component 子类,需要继承 Class 模板类。(个人觉的应该把 Class 改个名称,改为 ComponentRegister)。
class Config : public Class<Config, string> {public: Config() = delete; Config(string file_path) : config_file_(file_path) {} ~Config() { std::cout << "call ~Config()" << std::endl; };
void print() { std::cout << "config file: " << config_file_ << std::endl; };
private: string config_file_;};
// 方式2class ConfigComponent : public Config::Component {public: ConfigComponent() { std::cout << "call ConfigComponent()" << std::endl; }; ~ConfigComponent() { std::cout << "call ~ConfigComponent()" << std::endl; };
an<Config> create(string file_path) override { std::cout << "call ConfigComponent create()" << std::endl; return an<Config>(new Config(file_path)); };};
int main(int argc, const char* argv[]) { // 方式1: // Registry::instance().registerComponent("config", an<Component<Config>>(new Component<Config>));
// 方式2: Registry::instance().registerComponent("config", an<ConfigComponent>(new ConfigComponent())); an<Config> config = Config::require("config")->create("hamster.yaml"); config->print(); return 0;}组件注册需要调用 Registry::instance().registerComponent 方法。 对于有个性化初始化及清理逻辑的,可使用上面的方式 2 实现。
否则可以方式 1 ,更简单的注册组件。
通过 RIME 学习 C++ 系列:4
https://ihsiao.com/posts/rime/rime_learn_04/