开发模块化应用程序,我想在每个模块中注入一些辅助类。这应该是自动化的。请注意,我的帮助程序具有状态,因此我不能将它们设置为静态并将其包含在需要的位置。
我可以使用字符串键将所有帮助器存储在映射中,并使其可用于所有模块继承的抽象基类。
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宏,所以我不知道他们是否有能力。
答案 0 :(得分:1)
我想我看到你的困境是什么,但我没有很好的解决方案。但是,由于没有其他答案,我将贡献我的两分钱。
我使用一些策略的组合来帮助我解决这些问题:
如果帮助者的数量很高(例如超过2-3),我会创建一个包含所有指针的包含struct
(或简单class
)并传递该结构进入模块或子系统的构造函数。例如:
struct Platform { // I sometimes call it "Environment", etc.
FileHelper * file;
LogHelper * log;
MemoryHelper * mem;
StatsHelper * stats;
};
注意:这不是一个特别好或安全的解决方案,但它并不比管理不同的指针更糟糕,而且很简单。
所有上述假设帮助程序不依赖于模块(即它们处于较低的依赖级别抽象,并且对模块一无所知。)如果某些帮助程序更接近模块,那么,如果您开始想要注入模块上的模块依赖关系,上面的策略真的崩溃了。
在这些情况下(显然发生了很多)我发现集中的ModuleManager
单例(可能是一个全局对象)是最好的。您明确地将模块注册到其中,以及显式初始化顺序,并构建所有模块。模块可以要求此ModuleManager按名称引用其他模块(类似于模块指针的字符串映射),但它们只执行一次并以任何方式在内部存储指针,以方便快速访问。
但是,为了防止凌乱的生命周期和破坏顺序问题,无论何时构建或销毁模块,ModuleManager都会通过回调通知所有其他模块,因此他们有机会更新其内部指针以避免悬空指针和其他问题。
就是这样。顺便说一句,您可能想要调查与“服务定位器”模式相关的文章和实现。