如何在每個新模塊中自動注入輔助類? (How to automatically inject helper classes in each new module?)


問題描述

如何在每個新模塊中自動注入輔助類? (How to automatically inject helper classes in each new module?)

Developing a modular application, I want to inject some helper classes into each module. This should happen automated. Note that my helpers have state, so I can't just make them static and include them where needed.

I could store all helpers in a map with a string key and make it available to the abstract base class all modules inherit from.

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

Then inside a module, I could access helpers like this.

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

But instead, I would like to access the helpers like this.

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

To do so, at the moment I separately define members for all helpers in the module base class, and set them for each specific module.

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;

Is there a way to automate this, so that I don't have to change to module code when adding a new helper to the application, while remaining with the second syntax? I an not that familiar with C macros, so I don't know if they are capable of that.


參考解法

方法 1:

think I see what your dilemma is, but I have no good solution for it. However, since there are no other answers, I will contribute my two cents.

I use the combination of a few strategies to help me with these kinds of problems: 

  1. If the helper instance is truly module‑specific, I let the module itself create and manage it inside.
  2. If I don't want the module to know about the creation or destruction of the helper(s), or if the lifetime of the helper instance is not tied to the module that is using it, or if I want to share a helper instance among several modules, I create it outside and pass the reference to the entry‑point constructor of the module. Passing it to the constructor has the advantage of making the dependency explicit.
  3. If the number of the helpers are high (say more than 2‑3) I create an encompassing struct (or simple class) that just contains all the pointers and pass that struct into the constructor of the module or subsystem. For example: 

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

    Note: this is not a particularly nice or safe solution, but it's no worse than managing disparate pointers and it is straightforward.

All the above assumes that helpers have no dependency on modules (i.e. they are on a lower abstraction of dependency level and know nothing about modules.) If some helpers are closer to modules, that is, if you start to want to inject module‑on‑module dependencies into each other, the above strategies really break down.

In these cases (which obviously happen a lot) I have found that a centralized ModuleManager singleton (probably a global object) is the best. You explicitly register your modules into it, along with explicit order of initialization, and it constructs all the modules. The modules can ask this ModuleManager for a reference to other modules by name (kind of like a map of strings to module pointers,) but they do this once and store the pointers internally in any way they want for convenient and fast access.

However, to prevent messy lifetime and order‑of‑destruction issues, any time a module is constructed or destructed, the ModuleManager notifies all other modules via callbacks, so they have the chance to update their internal pointers to avoid dangling pointers and other problems.

That's it. By the way, you might want to investigate articles and implementations related to the "service locator" pattern.

(by danijaryzt)

參考文件

  1. How to automatically inject helper classes in each new module? (CC BY‑SA 3.0/4.0)

#Code-Generation #macros #architecture #module #C++






相關問題

關於編譯器中代碼生成的參考(中間表示、SSA、指令選擇、寄存器分配等)? (References on code generation in a compiler (intermediate representations, SSA, instruction selection, register allocation, etc.)?)

如何在每個新模塊中自動注入輔助類? (How to automatically inject helper classes in each new module?)

適用於Visual Studio的Python代碼生成器? (Python code generator for Visual Studio?)

為什么生成執行操作的 Java 代碼比“解釋器循環”運行得更慢? (Why does Java code generated to perform an operation run more slowly than an "interpreter loop"?)

ORM 映射的代碼生成工具 (code generation tool for ORM mapping)

Delphi 的 x86 代碼生成器框架 (x86 code generator framework for Delphi)

適用於 xpand 的 Actionscript 3 代碼美化器(MWE2 工作流程) (Actionscript 3 code beautifier for xpand (MWE2 Workflow))

Maven 中的代碼生成 (Code generation in Maven)

在自定義生成器中生成嵌套路由 (Generating nested routes in a custom generator)

是否有類似 JET(Java Emitter Templates)但沒有 Eclipse 依賴項的東西? (Is there something like JET (Java Emitter Templates) but without Eclipse-dependencies?)

Python函數,它返回自己的帶有參數的簽名 (Python function which returns its own signature with parameters)

為什麼 protobuf 更喜歡代碼生成器而不是運行時動態加載 (why protobuf prefer code-generator other than dynamic loading at runtime)







留言討論