当前位置: 首页 > news >正文

C++ 反射式注册表模式 (Registry Pattern) 笔记

一. 核心定义

注册表模式是一种通过字符串标识符在运行时动态创建对象的设计模式。它解决了 C++ 原生缺乏“反射”机制的问题,实现了类名与类实现之间的物理脱钩。

[ 具体类 (Circle/Rect) ] --(自动注册)--> [ 注册表 (Map) ] <--(查询创建)-- [ 业务逻辑 (Main) ]↑                                     ↑                               ↑隐藏实现                               单例中心                        只看基类

二、 核心组件拆解

1. 基类接口 (The Contract)

所有需要被反射出来的类,必须继承自一个统一的抽象基类,并实现其虚函数。

class Shape {
public:virtual void draw() = 0;virtual ~Shape() = default; // 必须有虚析构,防止内存泄漏
};

2. 注册表单例 (The Registry)

它是程序的核心“调度室”,内部维护一个映射表。

  • Key: 类名字符串(如 "Circle")。
  • Value: 生产该对象的“流水线”(函数指针或 std::function)。
#include <map>
#include <string>
#include <memory>
#include <functional>class ShapeRegistry {
public:// 生产线签名:不接收参数,返回一个基类指针using Creator = std::function<std::unique_ptr<Shape>()>;// 单例模式:确保全局只有一个调度室static ShapeRegistry& instance() {static ShapeRegistry reg;return reg;}// 登记:把生产线存入 mapvoid registerShape(const std::string& name, Creator creator) {registry_[name] = creator;}// 调用:按名生产std::unique_ptr<Shape> create(const std::string& name) {auto it = registry_.find(name);if (it != registry_.end()) {return it->second(); // 执行 Lambda,产出对象}return nullptr;}private:std::map<std::string, Creator> registry_;ShapeRegistry() = default; // 私有构造
};

三、 “最强大脑”的精髓:自注册 (Self-Registration)

这是反射模式最精妙的地方:如何让具体类在 main 函数运行前,自己跑去注册表报到?

1. 利用静态初始化

在 C++ 中,全局变量的初始化早于 main 函数执行。我们可以定义一个辅助类,利用它的构造函数来完成注册。

template<typename T>
class ShapeRegisterer {
public:ShapeRegisterer(const std::string& name) {// 在构造函数里调用单例进行登记ShapeRegistry::instance().registerShape(name, []() {return std::make_unique<T>();});}
};

2. 宏魔术 (The Macro)

为了让每个子类写起来更爽,我们用宏来生成这个静态变量。

#define REGISTER_SHAPE(className, key) \static ShapeRegisterer<className> global_##className##_reg(key)

四、 完整执行流程

当程序启动时,幕后发生了以下极其精彩的步骤:

  1. 加载期 (Pre-main)
  • 编译器扫描到 REGISTER_SHAPE(Circle, "circle")
  • 它创建一个全局静态对象 global_Circle_reg
  • 为了初始化这个变量,调用 ShapeRegisterer<Circle> 的构造函数。
  • 构造函数内部执行 ShapeRegistry::instance().registerShape(...)
  • 结果main 还没开始,map 已经填满了!
  1. 运行期 (Runtime)
  • main 函数根据配置文件或用户输入,拿到字符串 "circle"
  • 调用 create("circle")
  • 注册表返回一个 Circle 的实例,但 main 只把它当做 Shape* 使用。

五、 进阶:如何处理带参数的构造?

如果 Circle 需要半径参数 Circle(int radius),通常有三级进阶方案:

Level 1: 弱类型参数 (std::any)

注册表接收 std::vector<std::any>。缺点是类型不安全。

Level 2: 属性注入 (Property Injection)

先创建空对象,再调用 init(Config)。这是 Spring 框架最常用的逻辑。

auto obj = Registry::instance().create("Circle");
obj->setProperties(params); // params 可是 JSON 或 Map

Level 3: 变长模板 (Variadic Templates)

这是 C++11 后的极致方案。将注册表改为模板类,支持转发任意参数。


六、 为什么这是顶级设计?

  1. 解耦 (Decoupling)main.cpp 不需要引用 Circle.h。这意味着你可以让一个团队写 main,另一个团队写具体形状,双方互不干扰。
  2. 热插拔 (Hot-plugging):如果配合动态链接库(DLL/SO),你甚至可以在程序不重启的情况下,通过加载新的 DLL 来增加新的图形种类。
  3. 极简维护:增加新类只需要两步:继承基类 + 写一行 REGISTER_SHAPE
http://www.jsqmd.com/news/375254/

相关文章:

  • 解决leetcode第3836题.恰好k个下标对的最大得分
  • 深入解析:数据结构:初识“树”
  • 2026 最新仿真动物、仿真恐龙厂商推荐 TOP5 排行榜单,已权威测评 - 深度智识库
  • AI驱动的敏捷团队技能组:让Claude变身完整开发团队
  • 构建之法(1)
  • 2026板材十大品牌哪家专业 - 品牌推荐(官方)
  • 构建之法(2)
  • 聚焦2026电力工程:高低压开关柜及箱式变电站TOP5厂家深度推荐 - 深度智识库
  • 关于Keil(MDK)5.4灯新版本调试时无法查看单片机外设寄存器问题的解决方法
  • 港口建设模型技术方案分析
  • mysql--高级查询
  • 《构建之法》阅读笔记2
  • 《构建之法》阅读笔记3
  • 100%国产化芯片 RYOP284 40V、高性能、通用、零漂移运算放大器
  • 《构建之法》阅读笔记1
  • 医疗器械整机研发开发设计哪家强?2026创新突破全解析|行业前瞻 - 匠言榜单
  • mysql--高级查询(计算函数与分组查询)
  • 逐光致远,骏启新程——诺斯顿2026年会活动精彩回顾
  • Markdown学习笔记3分割线
  • openGauss 6.0 主备集群备份与恢复实战指南:基于 gs_probackup
  • 实用指南:【会员专享数据】2000-2022年全国逐年增强型植被指数(EVI)栅格数据
  • 洛谷 P7295 [USACO21JAN] Paint by Letters P 题解
  • 中科曙光拟募资80亿加码AI算力 信创产业步入“系统攻坚”新阶段
  • 为什么我劝你别急着买系统,先试试积木坞零代码
  • WC2026 游记
  • 【节点】[Ambient节点]原理解析与实际应用
  • 智能产品推荐AI系统的行业应用,AI应用架构师的案例分享
  • 掌握AI原生应用领域语义搜索,提升竞争力
  • 同步发电机三相短路暂态过程的计算方法与MATLAB/Simulink仿真
  • CSS3 多媒体查询实例【1】 - 教程