如何在每个新模块中自动注入助手类

How to automatically inject helper classes in each new module?

本文关键字:注入 模块 新模块      更新时间:2023-10-16

在开发模块化应用程序时,我想在每个模块中注入一些辅助类。这应该是自动化的。请注意,我的助手有状态,所以我不能只让它们成为静态的,并在需要的地方包含它们。

我可以用字符串键将所有助手存储在映射中,并使其可用于所有模块继承的抽象基类。

std::unordered_map<std::string, void*> helpers;
RendererModule renderer = new RendererModule(helpers); // argument is passed to
                                                       // base class constructor

然后在模块中,我可以访问这样的助手。

std::string file = (FileHelper*)helpers["file"]->Read("C:/file.txt");

但相反,我想访问这样的助手。

std::string file = File->Read("C:/file.txt");

为此,目前我为模块基类中的所有助手分别定义成员,并为每个特定模块设置它们。

FileHelper file = new FileHelper(); // some helper instances are passed to
                                    // multiple modules, while others are
                                    // newly created for each one
RendererModule renderer = new RendererModule();
renderer->File = file;

有没有一种方法可以自动实现这一点,这样在向应用程序添加新的帮助程序时,我就不必更改为模块代码,同时保留第二种语法?我不太熟悉C宏,所以我不知道它们是否能够做到这一点。

我明白你的困境是什么,但我没有很好的解决方案。但是,由于没有其他答案,我会贡献我的两分钱。

我使用一些策略的组合来帮助我解决这些类型的问题:

  1. 如果helper实例确实是特定于模块的,那么我让模块本身在内部创建和管理它
  2. 如果我不想让模块知道助手的创建或销毁,或者助手实例的生存期与使用它的模块无关,或者如果我想在几个模块之间共享一个助手实例,我会在外部创建它,并将引用传递给模块的入口点构造函数。将它传递给构造函数的好处是使依赖关系显式
  3. 如果助手的数量很高(比如说超过2-3),我会创建一个包含所有指针的struct(或简单class),并将该结构传递到模块或子系统的构造函数中。例如:

    struct Platform { // I sometimes call it "Environment", etc.
        FileHelper * file;
        LogHelper * log;
        MemoryHelper * mem;
        StatsHelper * stats;
    };
    

    注意:这不是一个特别好或安全的解决方案,但它并不比管理不同的指针更糟糕,而且很简单。

以上所有假设助手对模块没有依赖关系(即,他们处于依赖级别的较低抽象上,对模块一无所知。)如果一些助手更接近模块,也就是说,如果你开始想将模块对模块的依赖关系注入到彼此中,那么上述策略真的会崩溃。

在这些情况下(显然经常发生),我发现集中式ModuleManager单例(可能是全局对象)是最好的。您将模块显式注册到它中,并按照显式初始化顺序,它将构造所有模块。模块可以通过名称向ModuleManager请求对其他模块的引用(有点像字符串到模块指针的映射),但它们只做一次,并以任何方式在内部存储指针,以方便快速访问。

然而,为了防止混乱的寿命和销毁顺序问题,任何时候构建或销毁模块时,ModuleManager都会通过回调通知所有其他模块,这样它们就有机会更新内部指针,以避免悬挂指针和其他问题。

就是这样。顺便说一句,您可能想研究与"服务定位器"模式相关的文章和实现。