Morse's Site
598 字
3 分钟
通过 RIME 学习 C++ 系列:4
2024-06-08

组件的注册与调用#

在阅读 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/
作者
Morse Hsiao
发布于
2024-06-08
许可协议
CC BY-NC-SA 4.0