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_;
};
// 方式2
class 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://fuwari.vercel.app/posts/rime/rime_learn_04/